From 17409f3f112fb07238316466bd5b8110d0b6e6e3 Mon Sep 17 00:00:00 2001 From: Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com> Date: Sat, 23 Aug 2025 21:49:07 -0400 Subject: [PATCH] 2025/08/23 Update Added PEPS AI. Updated for PRC8 updates. --- README.md | 2 +- src/_removed/nw_i0_generic.nss | 1980 + src/_removed/nw_s0_heal.ncs | Bin 0 -> 2088 bytes src/_removed/nw_s0_heal.nss | 74 + src/include/inc_epicspelldef.nss | 143 +- src/include/inc_epicspellfnc.nss | 2 +- src/include/inc_infusion.nss | 481 + src/include/inc_lookups.nss | 42 +- src/include/inc_newspellbook.nss | 153 +- src/include/inc_switch_setup.nss | 18 +- src/include/moi_inc_moifunc.nss | 2 +- src/include/nw_inc_gff.nss | 623 + src/include/nw_inc_nui.nss | 852 +- src/include/prc_add_spell_dc.nss | 2 + src/include/prc_class_const.nss | 5 +- src/include/prc_effect_inc.nss | 49 +- src/include/prc_feat_const.nss | 101 +- src/include/prc_inc_castlvl.nss | 69 +- src/include/prc_inc_clsfunc.nss | 3 + src/include/prc_inc_combat.nss | 18 +- src/include/prc_inc_combmove.nss | 8 +- src/include/prc_inc_core.nss | 6 +- src/include/prc_inc_fork.nss | 12 +- src/include/prc_inc_function.nss | 10 +- src/include/prc_inc_json.nss | 750 + src/include/prc_inc_material.nss | 17 +- src/include/prc_inc_skills.nss | 12 +- src/include/prc_inc_spells.nss | 121 +- src/include/prc_inc_switch.nss | 35 +- src/include/prc_inc_turning.nss | 32 +- src/include/prc_inc_wpnrest.nss | 183 +- src/include/prc_ipfeat_const.nss | 11 +- src/include/prc_misc_const.nss | 4 + src/include/prc_nui_com_inc.nss | 530 + src/include/prc_nui_consts.nss | 47 +- src/include/prc_nui_lv_inc.nss | 3339 ++ ...{prc_nui_sc_inc.nss => prc_nui_sb_inc.nss} | 357 +- ...rc_nui_scd_inc.nss => prc_nui_sbd_inc.nss} | 2 +- src/include/prc_spell_const.nss | 90 +- src/include/prc_spellf_inc.nss | 3 + src/include/prc_template_con.nss | 1 + src/include/prc_x2_craft.nss | 531 +- src/include/prc_x2_itemprop.nss | 3 +- src/include/shd_inc_mystknwn.nss | 1 + src/include/shd_inc_shdfunc.nss | 6 +- src/include/tob_inc_tobfunc.nss | 1 + src/include/x2_inc_spellhook.nss | 205 +- src/module/dlg/nw_g_animal.dlg.json | 48353 +++++++++++++++- src/module/dlg/nw_g_fam.dlg.json | 24515 ++++++-- src/module/dlg/oc_ai_henchmen.dlg.json | 27180 +++++++++ src/module/ifo/module.ifo.json | 11 +- src/module/itp/creaturepalcus.itp.json | 2 +- src/module/nss/0c_assoc_actions.nss | 172 + src/module/nss/0c_cast_polymorp.nss | 18 + src/module/nss/0c_fire_henchmen.nss | 15 + src/module/nss/0c_get_convo.nss | 22 + src/module/nss/0c_get_henchman.nss | 25 + src/module/nss/0c_h_cast_spell.nss | 12 + src/module/nss/0c_henchmenspell.nss | 81 + src/module/nss/0c_if_a_magic_m.nss | 16 + src/module/nss/0c_if_ass_convo.nss | 132 + src/module/nss/0c_if_assoc_mode.nss | 22 + src/module/nss/0c_if_cntrspell.nss | 17 + src/module/nss/0c_if_com_script.nss | 16 + src/module/nss/0c_if_convo.nss | 21 + src/module/nss/0c_if_has_assoc.nss | 18 + src/module/nss/0c_if_has_class.nss | 28 + src/module/nss/0c_if_has_feat.nss | 22 + src/module/nss/0c_if_has_spell.nss | 26 + src/module/nss/0c_if_hen_leave.nss | 12 + src/module/nss/0c_if_identify.nss | 17 + src/module/nss/0c_if_not_master.nss | 11 + src/module/nss/0c_if_open_inven.nss | 13 + src/module/nss/0c_if_pickuploot.nss | 12 + src/module/nss/0c_if_polymorph.nss | 11 + src/module/nss/0c_if_scout.nss | 11 + src/module/nss/0c_if_skillrank.nss | 18 + src/module/nss/0c_if_taunt.nss | 15 + src/module/nss/0c_listhenchman.nss | 19 + src/module/nss/0c_no_com_script.nss | 27 + src/module/nss/0c_remove_effect.nss | 14 + src/module/nss/0c_summon_assoc.nss | 17 + src/module/nss/0c_use_feat.nss | 15 + src/module/nss/0e_c2_1_hb.nss | 16 + src/module/nss/0e_c2_7_ondeath.nss | 32 + src/module/nss/0e_ch_1_hb.nss | 14 + src/module/nss/0e_ch_7_ondeath.nss | 41 + src/module/nss/0e_do_combat_rnd.nss | 22 + src/module/nss/0e_gui_events.nss | 60 + src/module/nss/0e_m1_3_endround.nss | 46 + src/module/nss/0e_nui.nss | 1975 + src/module/nss/0e_nui_dm.nss | 700 + src/module/nss/0e_onclientload.nss | 23 + src/module/nss/0e_player_target.nss | 154 + src/module/nss/0e_prc_ch_events.nss | 78 + src/module/nss/0i_actions.nss | 2325 + src/module/nss/0i_associates.nss | 2192 + src/module/nss/0i_color.nss | 70 + src/module/nss/0i_combat.nss | 3498 ++ src/module/nss/0i_constants.nss | 667 + src/module/nss/0i_gui_events.nss | 1032 + src/module/nss/0i_items.nss | 1243 + src/module/nss/0i_main.nss | 1328 + src/module/nss/0i_menus.nss | 4823 ++ src/module/nss/0i_menus_dm.nss | 1386 + src/module/nss/0i_messages.nss | 88 + src/module/nss/0i_module.nss | 544 + src/module/nss/0i_nui.nss | 434 + src/module/nss/0i_player_target.nss | 793 + src/module/nss/0i_spells.nss | 2157 + src/module/nss/0i_states_cond.nss | 423 + src/module/nss/0i_talents.nss | 3098 + src/module/nss/0i_time.nss | 95 + src/module/nss/ai_a_ambusher.nss | 105 + src/module/nss/ai_a_atk_casters.nss | 159 + src/module/nss/ai_a_atk_nearest.nss | 80 + src/module/nss/ai_a_atk_warrior.nss | 159 + src/module/nss/ai_a_barbarian.nss | 87 + src/module/nss/ai_a_bard.nss | 83 + src/module/nss/ai_a_cleric.nss | 102 + src/module/nss/ai_a_cntrspell.nss | 69 + src/module/nss/ai_a_default.nss | 80 + src/module/nss/ai_a_defensive.nss | 77 + src/module/nss/ai_a_druid.nss | 86 + src/module/nss/ai_a_fighter.nss | 82 + src/module/nss/ai_a_flanker.nss | 117 + src/module/nss/ai_a_invisible.nss | 123 + src/module/nss/ai_a_monk.nss | 82 + src/module/nss/ai_a_no_cmb_mode.nss | 131 + src/module/nss/ai_a_paladin.nss | 110 + src/module/nss/ai_a_peaceful.nss | 81 + src/module/nss/ai_a_polymorphed.nss | 70 + src/module/nss/ai_a_ranged.nss | 129 + src/module/nss/ai_a_ranger.nss | 96 + src/module/nss/ai_a_rogue.nss | 83 + src/module/nss/ai_a_sorcerer.nss | 75 + src/module/nss/ai_a_taunter.nss | 53 + src/module/nss/ai_a_wizard.nss | 77 + src/module/nss/ai_ambusher.nss | 100 + src/module/nss/ai_barbarian.nss | 71 + src/module/nss/ai_bard.nss | 67 + src/module/nss/ai_cleric.nss | 68 + src/module/nss/ai_cntrspell.nss | 68 + src/module/nss/ai_coward.nss | 133 + src/module/nss/ai_default.nss | 49 + src/module/nss/ai_defensive.nss | 48 + src/module/nss/ai_dragon.nss | 51 + src/module/nss/ai_druid.nss | 70 + src/module/nss/ai_fighter.nss | 65 + src/module/nss/ai_flanker.nss | 102 + src/module/nss/ai_incorporeal.nss | 83 + src/module/nss/ai_invisible.nss | 93 + src/module/nss/ai_monk.nss | 65 + src/module/nss/ai_paladin.nss | 71 + src/module/nss/ai_polymorphed.nss | 55 + src/module/nss/ai_ranged.nss | 116 + src/module/nss/ai_ranger.nss | 79 + src/module/nss/ai_rogue.nss | 66 + src/module/nss/ai_shadow.nss | 77 + src/module/nss/ai_sorcerer.nss | 61 + src/module/nss/ai_taunter.nss | 78 + src/module/nss/ai_wizard.nss | 63 + src/module/nss/dmfi_db_biow_inc.nss | 2 +- src/module/nss/dmfi_db_nbde_inc.nss | 2 +- src/module/nss/hif_onenter.nss | 14 + src/module/nss/loot_inc_main.nss | 12 +- src/module/nss/mm_prc_spells.nss | 161 + src/module/nss/nw_c2_default1.nss | 159 +- src/module/nss/nw_c2_default2.nss | 255 +- src/module/nss/nw_c2_default3.nss | 106 +- src/module/nss/nw_c2_default4.nss | 129 +- src/module/nss/nw_c2_default5.nss | 93 +- src/module/nss/nw_c2_default6.nss | 128 +- src/module/nss/nw_c2_default8.nss | 42 +- src/module/nss/nw_c2_defaultb.nss | 180 +- src/module/nss/nw_c2_defaulte.nss | 82 +- src/module/nss/nw_ch_ac1.nss | 158 + src/module/nss/nw_ch_ac2.nss | 107 + src/module/nss/nw_ch_ac3.nss | 56 + src/module/nss/nw_ch_ac4.nss | 45 + src/module/nss/nw_ch_ac5.nss | 51 + src/module/nss/nw_ch_ac6.nss | 32 + src/module/nss/nw_ch_ac8.nss | 25 + src/module/nss/nw_ch_aca.nss | 46 + src/module/nss/nw_ch_acb.nss | 42 + src/module/nss/nw_ch_ace.nss | 60 + src/module/nss/nw_ch_summon_9.nss | 40 + src/module/nss/pc_savebuffs.nss | 182 + src/module/nss/pe_buffing.nss | 534 + src/module/nss/pe_crafting.nss | 2153 + src/module/nss/pe_debug.nss | 900 + src/module/nss/pe_henchmen.nss | 589 + src/module/nss/pe_mod_set.nss | 119 + src/module/nss/pe_test.nss | 227 + src/module/nss/pi_buffing.nss | 338 + src/module/nss/pi_crafting.nss | 717 + src/module/nss/pi_debug.nss | 200 + src/module/nss/pi_forcerest.nss | 70 + src/module/nss/pi_henchmen.nss | 209 + src/module/nss/pi_test.nss | 103 + src/module/nss/pinc_henchmen.nss | 1531 + src/module/nss/xx_pc_1_hb.nss | 79 + src/module/nss/xx_pc_2_percept.nss | 107 + src/module/nss/xx_pc_3_endround.nss | 60 + src/module/nss/xx_pc_4_convers.nss | 30 + src/module/nss/xx_pc_5_phyatked.nss | 29 + src/module/nss/xx_pc_6_damaged.nss | 27 + src/module/nss/xx_pc_8_disturb.nss | 21 + src/module/nss/xx_pc_b_castat.nss | 35 + src/module/nss/xx_pc_e_blocked.nss | 68 + 210 files changed, 148950 insertions(+), 6829 deletions(-) create mode 100644 src/_removed/nw_i0_generic.nss create mode 100644 src/_removed/nw_s0_heal.ncs create mode 100644 src/_removed/nw_s0_heal.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_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} (99%) create mode 100644 src/module/dlg/oc_ai_henchmen.dlg.json create mode 100644 src/module/nss/0c_assoc_actions.nss create mode 100644 src/module/nss/0c_cast_polymorp.nss create mode 100644 src/module/nss/0c_fire_henchmen.nss create mode 100644 src/module/nss/0c_get_convo.nss create mode 100644 src/module/nss/0c_get_henchman.nss create mode 100644 src/module/nss/0c_h_cast_spell.nss create mode 100644 src/module/nss/0c_henchmenspell.nss create mode 100644 src/module/nss/0c_if_a_magic_m.nss create mode 100644 src/module/nss/0c_if_ass_convo.nss create mode 100644 src/module/nss/0c_if_assoc_mode.nss create mode 100644 src/module/nss/0c_if_cntrspell.nss create mode 100644 src/module/nss/0c_if_com_script.nss create mode 100644 src/module/nss/0c_if_convo.nss create mode 100644 src/module/nss/0c_if_has_assoc.nss create mode 100644 src/module/nss/0c_if_has_class.nss create mode 100644 src/module/nss/0c_if_has_feat.nss create mode 100644 src/module/nss/0c_if_has_spell.nss create mode 100644 src/module/nss/0c_if_hen_leave.nss create mode 100644 src/module/nss/0c_if_identify.nss create mode 100644 src/module/nss/0c_if_not_master.nss create mode 100644 src/module/nss/0c_if_open_inven.nss create mode 100644 src/module/nss/0c_if_pickuploot.nss create mode 100644 src/module/nss/0c_if_polymorph.nss create mode 100644 src/module/nss/0c_if_scout.nss create mode 100644 src/module/nss/0c_if_skillrank.nss create mode 100644 src/module/nss/0c_if_taunt.nss create mode 100644 src/module/nss/0c_listhenchman.nss create mode 100644 src/module/nss/0c_no_com_script.nss create mode 100644 src/module/nss/0c_remove_effect.nss create mode 100644 src/module/nss/0c_summon_assoc.nss create mode 100644 src/module/nss/0c_use_feat.nss create mode 100644 src/module/nss/0e_c2_1_hb.nss create mode 100644 src/module/nss/0e_c2_7_ondeath.nss create mode 100644 src/module/nss/0e_ch_1_hb.nss create mode 100644 src/module/nss/0e_ch_7_ondeath.nss create mode 100644 src/module/nss/0e_do_combat_rnd.nss create mode 100644 src/module/nss/0e_gui_events.nss create mode 100644 src/module/nss/0e_m1_3_endround.nss create mode 100644 src/module/nss/0e_nui.nss create mode 100644 src/module/nss/0e_nui_dm.nss create mode 100644 src/module/nss/0e_onclientload.nss create mode 100644 src/module/nss/0e_player_target.nss create mode 100644 src/module/nss/0e_prc_ch_events.nss create mode 100644 src/module/nss/0i_actions.nss create mode 100644 src/module/nss/0i_associates.nss create mode 100644 src/module/nss/0i_color.nss create mode 100644 src/module/nss/0i_combat.nss create mode 100644 src/module/nss/0i_constants.nss create mode 100644 src/module/nss/0i_gui_events.nss create mode 100644 src/module/nss/0i_items.nss create mode 100644 src/module/nss/0i_main.nss create mode 100644 src/module/nss/0i_menus.nss create mode 100644 src/module/nss/0i_menus_dm.nss create mode 100644 src/module/nss/0i_messages.nss create mode 100644 src/module/nss/0i_module.nss create mode 100644 src/module/nss/0i_nui.nss create mode 100644 src/module/nss/0i_player_target.nss create mode 100644 src/module/nss/0i_spells.nss create mode 100644 src/module/nss/0i_states_cond.nss create mode 100644 src/module/nss/0i_talents.nss create mode 100644 src/module/nss/0i_time.nss create mode 100644 src/module/nss/ai_a_ambusher.nss create mode 100644 src/module/nss/ai_a_atk_casters.nss create mode 100644 src/module/nss/ai_a_atk_nearest.nss create mode 100644 src/module/nss/ai_a_atk_warrior.nss create mode 100644 src/module/nss/ai_a_barbarian.nss create mode 100644 src/module/nss/ai_a_bard.nss create mode 100644 src/module/nss/ai_a_cleric.nss create mode 100644 src/module/nss/ai_a_cntrspell.nss create mode 100644 src/module/nss/ai_a_default.nss create mode 100644 src/module/nss/ai_a_defensive.nss create mode 100644 src/module/nss/ai_a_druid.nss create mode 100644 src/module/nss/ai_a_fighter.nss create mode 100644 src/module/nss/ai_a_flanker.nss create mode 100644 src/module/nss/ai_a_invisible.nss create mode 100644 src/module/nss/ai_a_monk.nss create mode 100644 src/module/nss/ai_a_no_cmb_mode.nss create mode 100644 src/module/nss/ai_a_paladin.nss create mode 100644 src/module/nss/ai_a_peaceful.nss create mode 100644 src/module/nss/ai_a_polymorphed.nss create mode 100644 src/module/nss/ai_a_ranged.nss create mode 100644 src/module/nss/ai_a_ranger.nss create mode 100644 src/module/nss/ai_a_rogue.nss create mode 100644 src/module/nss/ai_a_sorcerer.nss create mode 100644 src/module/nss/ai_a_taunter.nss create mode 100644 src/module/nss/ai_a_wizard.nss create mode 100644 src/module/nss/ai_ambusher.nss create mode 100644 src/module/nss/ai_barbarian.nss create mode 100644 src/module/nss/ai_bard.nss create mode 100644 src/module/nss/ai_cleric.nss create mode 100644 src/module/nss/ai_cntrspell.nss create mode 100644 src/module/nss/ai_coward.nss create mode 100644 src/module/nss/ai_default.nss create mode 100644 src/module/nss/ai_defensive.nss create mode 100644 src/module/nss/ai_dragon.nss create mode 100644 src/module/nss/ai_druid.nss create mode 100644 src/module/nss/ai_fighter.nss create mode 100644 src/module/nss/ai_flanker.nss create mode 100644 src/module/nss/ai_incorporeal.nss create mode 100644 src/module/nss/ai_invisible.nss create mode 100644 src/module/nss/ai_monk.nss create mode 100644 src/module/nss/ai_paladin.nss create mode 100644 src/module/nss/ai_polymorphed.nss create mode 100644 src/module/nss/ai_ranged.nss create mode 100644 src/module/nss/ai_ranger.nss create mode 100644 src/module/nss/ai_rogue.nss create mode 100644 src/module/nss/ai_shadow.nss create mode 100644 src/module/nss/ai_sorcerer.nss create mode 100644 src/module/nss/ai_taunter.nss create mode 100644 src/module/nss/ai_wizard.nss create mode 100644 src/module/nss/hif_onenter.nss create mode 100644 src/module/nss/mm_prc_spells.nss create mode 100644 src/module/nss/nw_ch_ac1.nss create mode 100644 src/module/nss/nw_ch_ac2.nss create mode 100644 src/module/nss/nw_ch_ac3.nss create mode 100644 src/module/nss/nw_ch_ac4.nss create mode 100644 src/module/nss/nw_ch_ac5.nss create mode 100644 src/module/nss/nw_ch_ac6.nss create mode 100644 src/module/nss/nw_ch_ac8.nss create mode 100644 src/module/nss/nw_ch_aca.nss create mode 100644 src/module/nss/nw_ch_acb.nss create mode 100644 src/module/nss/nw_ch_ace.nss create mode 100644 src/module/nss/nw_ch_summon_9.nss create mode 100644 src/module/nss/pc_savebuffs.nss create mode 100644 src/module/nss/pe_buffing.nss create mode 100644 src/module/nss/pe_crafting.nss create mode 100644 src/module/nss/pe_debug.nss create mode 100644 src/module/nss/pe_henchmen.nss create mode 100644 src/module/nss/pe_mod_set.nss create mode 100644 src/module/nss/pe_test.nss create mode 100644 src/module/nss/pi_buffing.nss create mode 100644 src/module/nss/pi_crafting.nss create mode 100644 src/module/nss/pi_debug.nss create mode 100644 src/module/nss/pi_forcerest.nss create mode 100644 src/module/nss/pi_henchmen.nss create mode 100644 src/module/nss/pi_test.nss create mode 100644 src/module/nss/pinc_henchmen.nss create mode 100644 src/module/nss/xx_pc_1_hb.nss create mode 100644 src/module/nss/xx_pc_2_percept.nss create mode 100644 src/module/nss/xx_pc_3_endround.nss create mode 100644 src/module/nss/xx_pc_4_convers.nss create mode 100644 src/module/nss/xx_pc_5_phyatked.nss create mode 100644 src/module/nss/xx_pc_6_damaged.nss create mode 100644 src/module/nss/xx_pc_8_disturb.nss create mode 100644 src/module/nss/xx_pc_b_castat.nss create mode 100644 src/module/nss/xx_pc_e_blocked.nss diff --git a/README.md b/README.md index 76f1d46..b4b5d56 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,6 @@ Repository for the development of the PRC8 version of Lord of Terror, by Tolitz 2.) [Lord of Terror](https://neverwintervault.org/project/nwn1/module/lord-terror-diablo-campaign) -3.) [PRC8](https://gitea.raptio.us/Jaysyn/PRC8/src/branch/main/Release) +3.) [PRC8](https://gitea.raptio.us/Jaysyn/PRC8/releases) 4.) [CEP3](https://neverwintervault.org/project/nwnee/hakpak/combined/cep-3-community-expansion-pack) \ No newline at end of file diff --git a/src/_removed/nw_i0_generic.nss b/src/_removed/nw_i0_generic.nss new file mode 100644 index 0000000..9f9c3f5 --- /dev/null +++ b/src/_removed/nw_i0_generic.nss @@ -0,0 +1,1980 @@ +//:://///////////////////////////////////////////// +//:: Generic Scripting Include v1.0 +//:: NW_I0_GENERIC +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + + December 7 2002, Naomi Novik + Many functions removed to separate libraries: + + x0_i0_anims + PlayMobileAmbientAnimations_NonAvian + PlayMobileAmbientAnimations_Avian + (with PlayMobileAmbientAnimations changed to + just a call to one of these two) + PlayImmobileAmbientAnimations + + x0_i0_assoc + associate constants (NW_ASC_...) + GetPercentageHPLoss (only used in GetAssociateHealMaster) + SetAssociateState + GetAssociateState + ResetHenchmenState + AssociateCheck + GetAssociateHealMaster + GetFollowDistance + SetAssociateStartLocation + GetAssociateStartLocation + + x0_i0_behavior + behavior constants + SetBehaviorState + GetBehaviorState + + x0_i0_spawncond + OnSpawn condition constants + SetSpawnInCondition + GetSpawnInCondition + SetSpawnInLocals + SetListeningPatterns + + x0_i0_walkway + WalkWayPoints + RunNextCircuit + RunCircuit + CheckWayPoints + GetIsPostOrWalking + + x0_i0_talent + ALL the talent functions + + x0_i0_equip + Equipping functions + + x0_i0_match + Matching functions + + x0_i0_debug + MyPrintString + DebugPrintTalentId + newdebug + + x0_inc_generic + Pretty much everything else + + ***********************************************' + CHANGE SUMMARY + + + February 6 2003: Commented out the Henchman RespondToShout because now using + the newer bkRespondToShout function in x0_i0_henchman + + + September 18 2002: DetermineCombatRound broken into smaller functions + 19 : Removed randomness from Talent system. You can't + have smart AI and random behavior. Only healing + has the possiblity of being random. + + I may want to add the possibility of getting a + random talent only in the Talent filter if + something fails (*) + + + ******************************************** + WARNING THIS SCRIPT IS CHANGED AT YOUR PERIL + ******************************************** + + This is the master generic script and currently + handles all combat and some plot behavior + within NWN. If this script is tampered + with there is a chance of introducing game + breaking bugs. But other than that enjoy. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Sept 20, 2001 +//::////////////////////////////////////////////// + +//#include "x0_i0_assoc" - included in x0_inc_generic +//#include "x0_inc_generic" - included in x0_i0_talent +//#include "x0_i0_talent" - included in x0_i0_combat + +//#include "x0_i0_combat" - include in x0_i0_anims + +//#include "x0_i0_walkway" - include in x0_i0_anims +#include "x0_i0_behavior" +#include "x0_i0_anims" + + +/********************************************************************** + * CONSTANTS + **********************************************************************/ + +/********************************************************************** + * Flee and move constants + **********************************************************************/ + +int NW_GENERIC_FLEE_EXIT_FLEE = 0; +int NW_GENERIC_FLEE_EXIT_RETURN = 1; +int NW_GENERIC_FLEE_TELEPORT_FLEE = 2; +int NW_GENERIC_FLEE_TELEPORT_RETURN = 3; + +/********************************************************************** + * Shout constats + **********************************************************************/ + +// NOT USED +int NW_GENERIC_SHOUT_I_WAS_ATTACKED = 1; + +//IN OnDeath Script +int NW_GENERIC_SHOUT_I_AM_DEAD = 12; + +//IN TalentMeleeAttacked +int NW_GENERIC_SHOUT_BACK_UP_NEEDED = 13; + +int NW_GENERIC_SHOUT_BLOCKER = 2; + + +/********************************************************************** + * FUNCTION PROTOTYPES + **********************************************************************/ + +// * New Functions September - 2002 + + +// * The class-specific tactics have been broken out from DetermineCombatRound +// * for readability. This function determines the actual tactics each class +// * will use. +int chooseTactics(object oIntruder); + +// Adds all three of the class levels together. Used before +// GetHitDice became available +int GetCharacterLevel(object oTarget); + +//If using ambient sleep this will remove the effect +void RemoveAmbientSleep(); + +//Searches for the nearest locked object to the master +object GetLockedObject(object oMaster); + +/********************************************************************** + * DetermineCombatRound subfunctions + **********************************************************************/ + +// Used in DetermineCombatRound to keep a +// henchmen bashing doors. +int BashDoorCheck(object oIntruder = OBJECT_INVALID); + +// Determines which of a NPCs three classes to +// use in DetermineCombatRound +int DetermineClassToUse(); + + +/********************************************************************** + * Core AI Functions + **********************************************************************/ + +//:://///////////////////////////////////////////// +//:: DetermineCombatRound +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This function is the master function for the + generic include and is called from the main + script. This function is used in lieu of + any actual scripting. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//::////////////////////////////////////////////// +void DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10); + +//:://///////////////////////////////////////////// +//:: Respond To Shouts +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +// Allows the listener to react in a manner +// consistant with the given shout but only to one +// combat shout per round +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 25, 2001 +//::////////////////////////////////////////////// +//NOTE ABOUT COMMONERS +// Commoners are universal cowards. If you attack anyone +// they will flee for 4 seconds away from the attacker. +// However to make the commoners into a mob, make a single +// commoner at least 10th level of the same faction. +// If that higher level commoner is attacked or killed then +// the commoners will attack the attacker. They will disperse again +// after some of them are killed. Should NOT make multi-class +// creatures using commoners. +// +//NOTE ABOUT BLOCKERS +// It should be noted that the Generic Script for On Dialogue +// attempts to get a local set on the shouter by itself. +// This object represents the LastOpenedBy object. It is this +// object that becomes the oIntruder within this function. +// +//NOTE ABOUT INTRUDERS +// The intruder object is for cases where a placable needs to +// pass a LastOpenedBy Object or a AttackMyAttacker +// needs to make his attacker the enemy of everyone. +void RespondToShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID); + + +//******** PLOT FUNCTIONS + +// NPCs who have warning status set to TRUE will allow +// one 'free' attack by PCs from a non-hostile faction. +void SetNPCWarningStatus(int nStatus = TRUE); + +// NPCs who have warning status set to TRUE will allow +// one 'free' attack by PCs from a non-hostile faction. +int GetNPCWarningStatus(); + +// * Presently Does not work with the current implementation +// * of encounter triggers! +// +// This function works in tandem with an encounter +// to spawn in guards to fight for the attacked +// NPC. MAKE SURE THE ENCOUNTER TAG IS SET TO: +// +// "ENC_" + NPC TAG +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 29, 2001 +void SetSummonHelpIfAttacked(); + +// The target object flees to the specified +// way point and then destroys itself, to be +// respawned at a later point. For unkillable +// sign post characters who are not meant to fight +// back. +// This function is used only because ActionDoCommand can +// only accept void functions. +void CreateSignPostNPC(string sTag, location lLocal); + +// The target object flees to the specified +// way point and then destroys itself, to be +// respawned at a later point. For unkillable +// sign post characters who are not meant to fight +// back. +void ActivateFleeToExit(); + +// The target object flees to the specified +// way point and then destroys itself, to be +// respawned at a later point. For unkillable +// sign post characters who are not meant to fight +// back. +int GetFleeToExit(); + +// Checks that an item was unlocked. +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +void CheckIsUnlocked(object oLastObject); + +// This function is now just a wrapper around the functions +// PlayMobileAmbientAnimations_Nonavian() and +// PlayMobileAmbientAnimations_Avian(), in x0_i0_anims +void PlayMobileAmbientAnimations(); + +// Determines the special behavior used by the NPC. +// Generally all NPCs who you want to behave differently +// than the defualt behavior. +// For these behaviors, passing in a valid object will +// cause the creature to become hostile the the attacker. +void DetermineSpecialBehavior(object oIntruder = OBJECT_INVALID); + +// * Am I in a invisible or stealth state or sanctuary? +int InvisibleTrue(object oSelf = OBJECT_SELF); + +/********************************************************************** + * FUNCTION DEFINITIONS + **********************************************************************/ + +//:://///////////////////////////////////////////// +//:: AdjustBehaviorVariable +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* +Overriding "behavior" variables. +If a variable has been stored on the creature it overrides the above +class defaults +*/ +//::////////////////////////////////////////////// +//:: Created By: +//:: Created On: +//::////////////////////////////////////////////// + +int AdjustBehaviorVariable(int nVar, string sVarName) +{ + int nPlace =GetLocalInt(OBJECT_SELF, sVarName); + if (nPlace > 0) + { + return nPlace; + } + return nVar; // * return the original value +} + +//:://///////////////////////////////////////////// +//:: InvisibleBecome +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + A more intelligent invisibility solution, + along the lines of the one used in + the various end-user AIs. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: June 14, 2003 +//::////////////////////////////////////////////// +int InvisibleBecome(object oSelf = OBJECT_SELF) +{ + int iDarkness = FALSE; + if(GetHasSpell(SPELL_DARKNESS) && GetHasSpell(SPELL_DARKVISION)) iDarkness = TRUE; + if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY) || GetHasSpell(SPELL_INVISIBILITY) || + GetHasSpell(SPELL_INVISIBILITY_SPHERE) || (iDarkness) || GetHasSpell(SPELL_SANCTUARY) + || GetHasSpell(SPELL_ETHEREALNESS) + || GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oSelf) == TRUE) + { + + // * cannot already be invisible, otherwise what is the point + if(InvisibleTrue(oSelf) == FALSE) + { + // * this bit ported directly from Jasperre + // Can anyone see me? (has spell effects of X) + // * The point of this is to see if its even worthwhile to go invisbile + // * or will it be immediately dispeled. + object oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_TRUE_SEEING); + if(!GetIsObjectValid(oSeeMe)) + { + oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_SEE_INVISIBILITY); + // if(!GetIsObjectValid(oSeeMe)) + // { + // oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_INVISIBILITY_PURGE); + // } + } + + + if(!GetIsObjectValid(oSeeMe)) + { + int nDiff = GetCombatDifficulty(oSelf, TRUE); + //SpeakString(IntToString(nDiff)); + if (nDiff > -1) + { + + ClearActions(1001); + if (iDarkness==TRUE) + { + ActionCastSpellAtObject(SPELL_DARKVISION, oSelf); + ActionCastSpellAtObject(SPELL_DARKNESS, oSelf); + return TRUE; + } + if (GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oSelf) == TRUE) + { + ActionCastSpellAtObject(SPELL_IMPROVED_INVISIBILITY, oSelf); + return TRUE; + } + else + if (GetHasSpell(SPELL_INVISIBILITY, oSelf) == TRUE) + { + ActionCastSpellAtObject(SPELL_INVISIBILITY, oSelf); + return TRUE; + } + else + if (GetHasSpell(SPELL_INVISIBILITY_SPHERE, oSelf) == TRUE) + { + ActionCastSpellAtObject(SPELL_INVISIBILITY_SPHERE, oSelf); + return TRUE; + } + else + if (GetHasSpell(SPELL_ETHEREALNESS, oSelf) == TRUE) + { + ActionCastSpellAtObject(SPELL_ETHEREALNESS, oSelf); + return TRUE; + } + else + if (GetHasSpell(SPELL_SANCTUARY, oSelf) == TRUE) + { + ActionCastSpellAtObject(SPELL_SANCTUARY, oSelf); + return TRUE; + } + else + if (GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oSelf)) + // * go into stealth mode + { + // SpeakString("Attempting stealth mode"); + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); + WrapperActionAttack(GetNearestEnemy()); + return TRUE; + } + + } + } + }// is NOT invisible + } + return FALSE; +} + +//:://///////////////////////////////////////////// +//:: InvisibleTrue +//:: Copyright (c) 2003 Bioware Corp. +//::////////////////////////////////////////////// +/* + Returns TRUE if oSelf is hidden either + magically or via stealth + +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 14, 2003 +//::////////////////////////////////////////////// + +int InvisibleTrue(object oSelf =OBJECT_SELF) +{ + if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oSelf) || GetHasEffect(EFFECT_TYPE_IMPROVEDINVISIBILITY, oSelf) + || (GetHasSpellEffect(SPELL_DARKNESS, oSelf) && GetHasSpellEffect(SPELL_DARKVISION, oSelf)) + || GetActionMode(oSelf, ACTION_MODE_STEALTH) || GetHasEffect(EFFECT_TYPE_SANCTUARY, oSelf) + || GetHasEffect(EFFECT_TYPE_ETHEREAL, oSelf)) + { + return TRUE; + + } + return FALSE; +} + +// * Returns true if a wizard or sorcerer and wearing armor +int GetShouldNotCastSpellsBecauseofArmor(object oTarget, int nClass) +{ + + if (GetArcaneSpellFailure(oTarget) > 5 && (nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_WIZARD)) + { + return TRUE; + } + return FALSE; +} + + +//:://///////////////////////////////////////////// +//:: chooseTactics +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Separated this function out from DetermineCombatRound + for readibility +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: September 2002 +//::////////////////////////////////////////////// + +int chooseTactics(object oIntruder) +{ + + // SELF PRESERVATION: Always attempt to heal self first + if(TalentHealingSelf() == TRUE) return 99; //Use spells and potions + + // Next, try the special tactics routines + // specific to XP1 + if (SpecialTactics(oIntruder)) return 99; + + // * These constants in ChooseTactics routine + // * remember previous rounds choices + + int MEMORY_OFFENSE_MELEE = 0; + int MEMORY_DEFENSE_OTHERS = 1; + int MEMORY_DEFENSE_SELF = 2; + int MEMORY_OFFENSE_SPELL = 3; + + // * If defensive last round, try to be offensive this round + // * this is to prevent wasting time on multiple protections + int nPreviousMemory = GetLocalInt(OBJECT_SELF, "NW_L_MEMORY"); + + int nClass = DetermineClassToUse(); + + int nOffense, nCompassion, nMagic, nCrazy = 0; + + // * Defaulted high so unspecified classes will not be cowards + nOffense = 50; + + nCompassion = 25; + + // * Defaulted this high because non standard creatures + // * with spells should try and use them. + nMagic = 55; + + // * setup base BEHAVIOR + switch (nClass) + { + case CLASS_TYPE_COMMONER: + // Commoners should run away from fights + //SpawnScriptDebugger(); + nOffense = 0; nCompassion = 0; nMagic = 0; break; + case CLASS_TYPE_PALEMASTER: + case CLASS_TYPE_WIZARD: + case CLASS_TYPE_SORCERER: + // SpawnScriptDebugger(); + nOffense = 40; nCompassion = 40; nMagic = 100; break; + case CLASS_TYPE_BARD: + case CLASS_TYPE_HARPER: + case CLASS_TYPE_DRAGONDISCIPLE: + { + if(TalentBardSong() == TRUE) return 99; + nOffense = 40; nCompassion = 42; nMagic = 43; break; + } + case CLASS_TYPE_CLERIC: + case CLASS_TYPE_DRUID: + case CLASS_TYPE_SHIFTER: + { + nOffense = 40; + nCompassion = 45; + nMagic = 44; + // * Clerics shouldn't constantly cast spells + if (nPreviousMemory != MEMORY_OFFENSE_MELEE) + nMagic = Random(50) + 1; + break; + } + case CLASS_TYPE_PALADIN : + case CLASS_TYPE_RANGER : + nOffense = 40; nCompassion = 25; nMagic = Random(50) + 1; break; + case CLASS_TYPE_BARBARIAN: + { + // SpawnScriptDebugger(); + // * GetHasFeat(...) does not work correctly with no-leveled up + // * characters. So for now, only Xanos gets to do this. + string sTag = GetTag(OBJECT_SELF); + if (sTag == "x0_hen_xan" || sTag == "x2_hen_daelan") + { + if (GetHasFeatEffect(FEAT_BARBARIAN_RAGE) == FALSE) + { + + if (GetHasFeat(FEAT_BARBARIAN_RAGE) == TRUE) + { + ActionUseFeat(FEAT_BARBARIAN_RAGE, OBJECT_SELF); + return 99; + } + } + } + nOffense = 50; nCompassion = 25; nMagic = 20; break; + // * set high magic to use rage + // * suggestion don't give barbarians lots of magic or else they will fight oddly + } + case CLASS_TYPE_WEAPON_MASTER: + case CLASS_TYPE_ARCANE_ARCHER: + case CLASS_TYPE_BLACKGUARD: + case CLASS_TYPE_SHADOWDANCER: + case CLASS_TYPE_DWARVENDEFENDER: + case CLASS_TYPE_ASSASSIN: + case CLASS_TYPE_FIGHTER: + case CLASS_TYPE_ROGUE : //SpawnScriptDebugger(); + case CLASS_TYPE_MONK : + nOffense = 40; nCompassion = 0; nMagic = 0; break; + case CLASS_TYPE_UNDEAD: + nOffense = 40; nCompassion = 40; nMagic = 40; break; + case CLASS_TYPE_OUTSIDER: + { + nOffense = 40; nCompassion = 0; nMagic = 40; + if (GetAlignmentGoodEvil(OBJECT_SELF) == ALIGNMENT_GOOD) + { + nCompassion = 40; + } + break; + } + case CLASS_TYPE_CONSTRUCT: + case CLASS_TYPE_ELEMENTAL: + nOffense = 40; nCompassion = 0; nMagic = 40; break; + case CLASS_TYPE_DRAGON: + nOffense = 40; nCompassion = 20; nMagic = 40; break; + default: + nOffense = 7; nCompassion = 7; nMagic = 7; break; + } + + + + // MyPrintString("Made it past the class-specific settings"); + + + // ************************************ + // * MODIFY BEHAVIOR FOR SPECIAL CASES + // ************************************ + if (GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD) + nCompassion = nCompassion - 20; + + // Randomize things a bit + nOffense = Random(10 + nCrazy) + nOffense; + nMagic = Random(10 + nCrazy) + nMagic; + nCompassion = Random(10 + nCrazy) + nCompassion; + + + + // * if your opponent is close to you, then increase offense + // * as casting defensive abilities when enemies are close + // * is generally not a good idea. + // * Dec 18 2002: If you have Combat Casting, you'll still be more + // * liable to use defensive abilities + if (GetIsObjectValid(oIntruder) && !GetHasFeat(FEAT_COMBAT_CASTING)) + { + if (GetDistanceToObject(oIntruder) <= 5.0) { + nOffense = nOffense + 20; + nMagic = nMagic - 20; + } + } + + // * If enemies are further away, more chance of doing magic + if (GetDistanceToObject(oIntruder) > 3.0) + nMagic = nMagic + 15; + + // * Dec 18 2002: Add your level to your magic rating + nMagic = nMagic + GetHitDice(OBJECT_SELF); + + + // ************************************** + // * CHOOSE TALENT TO USE + // ************************************** + + //SpawnScriptDebugger(); + + // * If defensive last round, try to be offensive this round + // * this is to prevent wasting time on multiple protections + if ((nPreviousMemory == MEMORY_DEFENSE_OTHERS) + || (nPreviousMemory == MEMORY_DEFENSE_SELF)) + { + nOffense = nOffense + 40; + } + + + // April 2003 + // If in rage should be almost no chance of doing magic + // * June 2003 + // * If has more than 5% chance of spell failure don't try casting + if (GetHasFeatEffect(FEAT_BARBARIAN_RAGE)== TRUE || GetShouldNotCastSpellsBecauseofArmor(OBJECT_SELF, nClass) == TRUE + || GetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING") == 10) + { + nMagic = 0; + } + + + + + // ************** + // * JULY 12 2003 + // * Overriding "behavior" variables. + // * If a variable has been stored on the creature it overrides the above + // * class defaults + // * JULY 28 2003 + // * changed this so that its an additive process, not an overrwrite. + // * gives more flexiblity. + // ************** + nMagic = nMagic + AdjustBehaviorVariable(nMagic, "X2_L_BEH_MAGIC"); + nOffense = nOffense + AdjustBehaviorVariable(nOffense, "X2_L_BEH_OFFENSE"); + nCompassion = nCompassion + AdjustBehaviorVariable(nCompassion, "X2_L_BEH_COMPASSION"); + + + // * Dragon Disciple Breath + if (GetHasFeat(FEAT_DRAGON_DIS_BREATH) == TRUE && Random(100) > 50) + { + ClearActions(2000); + ActionCastSpellAtObject(690, GetNearestEnemy(), METAMAGIC_ANY, TRUE); + DecrementRemainingFeatUses(OBJECT_SELF, FEAT_DRAGON_DIS_BREATH); + return 99; + } + + + // * If invisbile of any sort, become Defensive and + // * magical to use any buffs you may have + // * This behavior variable setting should override all others + // * October 22 2003 - Lines 690 and 713 modified to only work if magic + // * setting has not been turned off. Nathyrra always going invisible + // * can be annoying. + if (InvisibleTrue(OBJECT_SELF) == TRUE && nMagic > 0) + { + // SpawnScriptDebugger(); + // * if wounded at all take this time to heal self + // * since I am invisible there is little danger from doing this + if (GetCurrentHitPoints(OBJECT_SELF) < GetMaxHitPoints(OBJECT_SELF)) + { + if(TalentHealingSelf(TRUE) == TRUE) return 99; + } + + nOffense = 7; + nMagic = 100; + + if (GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == TRUE) + { + nOffense = 100; // * if in stealth attempt sneak attacks + } + } + else + // ************** + // * JULY 14 2003 + // * Attempt To Go Invisible + // ************** + if (InvisibleBecome() == TRUE && nMagic > 0) + return 99; + + // PHYSICAL, NO OFFENSE + if (nOffense <= 5) + { + //SpawnScriptDebugger(); + //SpeakString("fleeing"); + if (TalentFlee(oIntruder) == TRUE) return 99; + } + + // protect others: MAGICAL, DEFENSE, COMPASSION + if ((nOffense<= 50) && (nMagic > 50) && (nCompassion > 50)) + { + SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", MEMORY_DEFENSE_OTHERS); + if (TalentHeal() == TRUE) return 99; + if (TalentCureCondition() == TRUE) return 99; + if (TalentUseProtectionOthers() == TRUE) return 99; + if (TalentEnhanceOthers() == TRUE) return 99; + + // * Temporarily be non-compassionate to buff self + // * if we got to this point. + nCompassion = 0; + } + + // protectself: MAGICAL, DEFENSE, NO COMPASSION + if ((nOffense<= 50) && (nMagic > 50) && (nCompassion <=50)) + { + SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", MEMORY_DEFENSE_SELF); + + /* Dec 19 2002: + Against spell-casters, cast protection spells more often + */ + int nClass = GetClassByPosition(1,oIntruder); + if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER + || nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_DRUID) + { + if (TalentSelfProtectionMantleOrGlobe()) + return 99; + } + + if(TalentUseProtectionOnSelf() == TRUE) return 99; + if(TalentUseEnhancementOnSelf() == TRUE) return 99; + if(TalentPersistentAbilities() == TRUE) return 99; + // int TalentAdvancedBuff(float fDistance); + + //Used for Potions of Enhancement and Protection + if(TalentBuffSelf() == TRUE) return 99; + + if(TalentAdvancedProtectSelf() == TRUE) return 99; + if(TalentSummonAllies() == TRUE) return 99; + if(TalentSeeInvisible() == TRUE) return 99; + if(TalentMeleeAttacked(oIntruder) == TRUE) return 99; + if(TalentRangedAttackers(oIntruder) == TRUE) return 99; + if(TalentRangedEnemies(oIntruder) == TRUE) return 99; + + + } + + // MAGICAL, OFFENSE + if (nMagic > 50) + { + // // MyPrintString("in offensive spell"); + // SpawnScriptDebugger(); + SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", MEMORY_OFFENSE_SPELL); + if (TalentUseTurning() == TRUE) return 99; + if (TalentSpellAttack(oIntruder) == TRUE) return 99; + } + + // If we got here, we're going to melee offense + SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", MEMORY_OFFENSE_MELEE); + + // PHYSICAL, OFFENSE (if nothing else applies) + if (TryKiDamage(oIntruder) == TRUE) return 99; + if (TalentSneakAttack() == TRUE) return 99; + if (TalentDragonCombat(oIntruder)) {return 99;} + if (TalentMeleeAttack(oIntruder) == TRUE) return 99; + + + object oHostile = GetNearestSeenEnemy(); + + // * Feb 17 2003: This error could happen in the situation that someone + // * went into combat mode and their 'hostility' ended while going through ChooseTactics + if (GetIsObjectValid(oHostile) == TRUE) + { + + // * BK if it returns this it means the AI found nothing + // * Appropriate to do + //SpeakString("BUG!!!!!!!!!!!!!!!!!!!!!!!! (Let Brent Knowles know about this. Supply savegame) Nothing valid to do !!!!!!!!!!!!!!!!!!!!!"); + //SpeakString("BUG!! Magic " + IntToString(nMagic) + " Compassion " + IntToString(nCompassion) + " Offense " + IntToString(nOffense)); + } + return 1; + +} // * END of choosetactics + +//:://///////////////////////////////////////////// +//:: __InCombatRound +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Tests to see if already running a determine + combatround this round. +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 11 2003 +//::////////////////////////////////////////////// +int __InCombatRound() +{ + + // * if just in attackaction, turn combat round off + // * if simply fighting it is okay to turn the combat round off + // * and try again because it doesn't hurt an attackaction + // * to be reiniated whereas it does break a spell + int nCurrentAction = GetCurrentAction(OBJECT_SELF); + if (nCurrentAction == ACTION_ATTACKOBJECT || nCurrentAction == ACTION_INVALID || nCurrentAction == ACTION_MOVETOPOINT) + { + return FALSE; + } + if (GetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND") == TRUE) + { + //SpeakString("DEBUG:: In Combat Round, busy."); + return TRUE; + } + return FALSE; +} +//:://///////////////////////////////////////////// +//:: __TurnCombatRoundOn +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Will set the exclusion variable on whether + in combat or not. + This is to prevent multiple firings + of determinecombatround in one round +*/ +//::////////////////////////////////////////////// +//:: Created By: Brent +//:: Created On: July 11 2003 +//::////////////////////////////////////////////// + +void __TurnCombatRoundOn(int bBool) +{ + if (bBool == TRUE) + { + SetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND", TRUE); + } + else + { + // * delay it turning off like an action + ActionDoCommand(SetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND", FALSE)); + } +} +//:://///////////////////////////////////////////// +//:: DetermineCombatRound +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This function is the master function for the + generic include and is called from the main + script. This function is used in lieu of + any actual scripting. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//::////////////////////////////////////////////// + +void DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10) +{ + // MyPrintString("************** DETERMINE COMBAT ROUND START *************"); + // MyPrintString("************** " + GetTag(OBJECT_SELF) + " ************"); + + // ---------------------------------------------------------------------------------------- + // May 2003 + // Abort out of here, if petrified + // ---------------------------------------------------------------------------------------- + if (GetHasEffect(EFFECT_TYPE_PETRIFY, OBJECT_SELF) == TRUE) + { + return; + } + + // ---------------------------------------------------------------------------------------- + // Oct 06/2003 - Georg Zoeller, + // Fix for ActionRandomWalk blocking the action queue under certain circumstances + // ---------------------------------------------------------------------------------------- + if (GetCurrentAction() == ACTION_RANDOMWALK) + { + ClearAllActions(); + } + + // ---------------------------------------------------------------------------------------- + // July 27/2003 - Georg Zoeller, + // Added to allow a replacement for determine combat round + // If a creature has a local string variable named X2_SPECIAL_COMBAT_AI_SCRIPT + // set, the script name specified in the variable gets run instead + // see x2_ai_behold for details: + // ---------------------------------------------------------------------------------------- + string sSpecialAI = GetLocalString(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT"); + if (sSpecialAI != "") + { + SetLocalObject(OBJECT_SELF,"X2_NW_I0_GENERIC_INTRUDER", oIntruder); + ExecuteScript(sSpecialAI, OBJECT_SELF); + if (GetLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK")) + { + DeleteLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK"); + return; + } + } + + + // ---------------------------------------------------------------------------------------- + // DetermineCombatRound: EVALUATIONS + // ---------------------------------------------------------------------------------------- + if(GetAssociateState(NW_ASC_IS_BUSY)) + { + return; + } + + if(BashDoorCheck(oIntruder)) {return;} + + // ---------------------------------------------------------------------------------------- + // BK: stop fighting if something bizarre that shouldn't happen, happens + // ---------------------------------------------------------------------------------------- + + if (bkEvaluationSanityCheck(oIntruder, GetFollowDistance()) == TRUE) + return; + + // ** Store HOw Difficult the combat is for this round + int nDiff = GetCombatDifficulty(); + SetLocalInt(OBJECT_SELF, "NW_L_COMBATDIFF", nDiff); + + // MyPrintString("COMBAT: " + IntToString(nDiff)); + + // ---------------------------------------------------------------------------------------- + // If no special target has been passed into the function + // then choose an appropriate target + // ---------------------------------------------------------------------------------------- + if (GetIsObjectValid(oIntruder) == FALSE) + oIntruder = bkAcquireTarget(); + + + if (GetIsDead(oIntruder) == TRUE) + { + // ---------------------------------------------------------------------------------------- + // If for some reason my target is dead, then leave + // the poor guy alone. Jeez. What kind of monster am I? + // ---------------------------------------------------------------------------------------- + return; + } + + // ---------------------------------------------------------------------------------------- + /* + JULY 11 2003 + If in combat round already (variable set) do not enter it again. + This is meant to prevent multiple calls to DetermineCombatRound + from happening during the *same* round. + + This variable is turned on at the start of this function call. + It is turned off at each "return" point for this function + */ + // ---------------------------------------------------------------------------------------- + if (__InCombatRound() == TRUE) + { + return; + } + + __TurnCombatRoundOn(TRUE); + + // ---------------------------------------------------------------------------------------- + // DetermineCombatRound: ACTIONS + // ---------------------------------------------------------------------------------------- + if(GetIsObjectValid(oIntruder)) + { + + if(TalentPersistentAbilities()) // * Will put up things like Auras quickly + { + __TurnCombatRoundOn(FALSE); + return; + } + + // ---------------------------------------------------------------------------------------- + // BK September 2002 + // If a succesful tactic has been chosen then + // exit this function directly + // ---------------------------------------------------------------------------------------- + + if (chooseTactics(oIntruder) == 99) + { + __TurnCombatRoundOn(FALSE); + return; + } + + // ---------------------------------------------------------------------------------------- + // This check is to make sure that people do not drop out of + // combat before they are supposed to. + // ---------------------------------------------------------------------------------------- + + object oNearEnemy = GetNearestSeenEnemy(); + DetermineCombatRound(oNearEnemy); + + return; + } + __TurnCombatRoundOn(FALSE); + + // ---------------------------------------------------------------------------------------- + // This is a call to the function which determines which + // way point to go back to. + // ---------------------------------------------------------------------------------------- + ClearActions(CLEAR_NW_I0_GENERIC_658); + SetLocalObject(OBJECT_SELF, + "NW_GENERIC_LAST_ATTACK_TARGET", + OBJECT_INVALID); + WalkWayPoints(); +} + + + +//:://///////////////////////////////////////////// +//:: Respond To Shouts +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Allows the listener to react in a manner + consistant with the given shout but only to one + combat shout per round +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 25, 2001 +//::////////////////////////////////////////////// + +//NOTE ABOUT COMMONERS +/* + Commoners are universal cowards. If you attack anyone they will flee for 4 seconds away from the attacker. + However to make the commoners into a mob, make a single commoner at least 10th level of the same faction. + If that higher level commoner is attacked or killed then the commoners will attack the attacker. They will disperse again + after some of them are killed. Should NOT make multi-class creatures using commoners. +*/ +//NOTE ABOUT BLOCKERS +/* + It should be noted that the Generic Script for On Dialogue attempts to get a local set on the shouter by itself. + This object represents the LastOpenedBy object. It is this object that becomes the oIntruder within this function. +*/ + +//NOTE ABOUT INTRUDERS +/* + The intruder object is for cases where a placable needs to pass a LastOpenedBy Object or a AttackMyAttacker + needs to make his attacker the enemy of everyone. +*/ + +void RespondToShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID) +{ + + // Pausanias: Do not respond to shouts if you've surrendered. + int iSurrendered = GetLocalInt(OBJECT_SELF,"Generic_Surrender"); + if (iSurrendered) return; + + switch (nShoutIndex) + { + case 1://NW_GENERIC_SHOUT_I_WAS_ATTACKED: + { + object oTarget = oIntruder; + if(!GetIsObjectValid(oTarget)) + { + oTarget = GetLastHostileActor(oShouter); + } + if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) + { + if(!GetLevelByClass(CLASS_TYPE_COMMONER)) + { + if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget())) + { + if(GetIsObjectValid(oTarget)) + { + if(!GetIsFriend(oTarget) && GetIsFriend(oShouter)) + { + RemoveAmbientSleep(); + //DetermineCombatRound(oTarget); + DetermineCombatRound(GetLastHostileActor(oShouter)); + } + } + } + } + else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10) + { + WrapperActionAttack(GetLastHostileActor(oShouter)); + } + else + { + DetermineCombatRound(oIntruder); + } + } + else + { + DetermineSpecialBehavior(); + } + } + break; + + case 2://NW_GENERIC_SHOUT_MOB_ATTACK: + { + if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) + { + + //Is friendly check to make sure that only like minded commoners attack. + if(GetIsFriend(oShouter)) + { + WrapperActionAttack(GetLastHostileActor(oShouter)); + } + //if(TalentMeleeAttack()) {return;} + } + else + { + DetermineSpecialBehavior(); + } + } + break; + + case 3://NW_GENERIC_SHOUT_I_AM_DEAD: + { + if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) + { + //Use I was attacked script above + if(!GetLevelByClass(CLASS_TYPE_COMMONER)) + { + if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget())) + { + if(GetIsObjectValid(GetLastHostileActor(oShouter))) + { + if(!GetIsFriend(GetLastHostileActor(oShouter)) && GetIsFriend(oShouter)) + { + DetermineCombatRound(GetLastHostileActor(oShouter)); + } + } + } + } + else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10) + { + WrapperActionAttack(GetLastHostileActor(oShouter)); + } + else + { + DetermineCombatRound(); + } + + } + else + { + DetermineSpecialBehavior(); + } + } + break; + //For this shout to work the object must shout the following + //string sHelp = "NW_BLOCKER_BLK_" + GetTag(OBJECT_SELF); + case 4: //BLOCKER OBJECT HAS BEEN DISTURBED + { + if(!GetLevelByClass(CLASS_TYPE_COMMONER)) + { + if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget())) + { + if(GetIsObjectValid(oIntruder)) + { + SetIsTemporaryEnemy(oIntruder); + DetermineCombatRound(oIntruder); + } + } + } + else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10) + { + WrapperActionAttack(oIntruder); + } + else + { + DetermineCombatRound(); + } + } + break; + + case 5: //ATTACK MY TARGET + { + AdjustReputation(oIntruder, OBJECT_SELF, -100); + if(GetIsFriend(oShouter)) + { + SetIsTemporaryEnemy(oIntruder); + ClearActions(CLEAR_NW_I0_GENERIC_834); + DetermineCombatRound(oIntruder); + } + } + break; + + case 6: //CALL_TO_ARMS + { + //This was once commented out. + DetermineCombatRound(); + } + break; + + //ASSOCIATE SHOUT RESPONSES ****************************************************************************** + + /* This was moved into X0_I0_HENCHMAN as bkRespondToHenchmenShout + case ASSOCIATE_COMMAND_ATTACKNEAREST: //Used to de-activate AGGRESSIVE DEFEND MODE + { + ResetHenchmenState(); + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + DetermineCombatRound(); + } + break; + + case ASSOCIATE_COMMAND_FOLLOWMASTER: //Only used to retreat, or break free from Stand Ground Mode + { + ResetHenchmenState(); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + DelayCommand(2.5, VoiceCanDo()); + + if(GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH)) + { + //ActionUseSkill(SKILL_HIDE, OBJECT_SELF); + } + if(GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH)) + { + ActionUseSkill(SKILL_SEARCH, OBJECT_SELF); + } + ActionForceFollowObject(GetMaster(), GetFollowDistance()); + SetAssociateState(NW_ASC_IS_BUSY); + DelayCommand(5.0, SetAssociateState(NW_ASC_IS_BUSY, FALSE)); + } + break; + + case ASSOCIATE_COMMAND_GUARDMASTER: //Used to activate AGGRESSIVE DEFEND MODE + { + ResetHenchmenState(); + DelayCommand(2.5, VoiceCanDo()); + //Companions will only attack the Masters Last Attacker + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + if(GetIsObjectValid(GetLastHostileActor(GetMaster()))) + { + DetermineCombatRound(GetLastHostileActor(GetMaster())); + } + } + break; + + case ASSOCIATE_COMMAND_HEALMASTER: //Ignore current healing settings and heal me now + { + ResetHenchmenState(); + //SetCommandable(TRUE); + if(TalentCureCondition()) {DelayCommand(2.0, VoiceCanDo()); return;} + if(TalentHeal(TRUE)) {DelayCommand(2.0, VoiceCanDo()); return;} + DelayCommand(2.5, VoiceCannotDo()); + } + break; + + case ASSOCIATE_COMMAND_MASTERFAILEDLOCKPICK: //Check local for Re-try locked doors and + { + if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS)) + { + int bValid = TRUE; + object oLastObject = GetLockedObject(GetMaster()); + int nSkill = GetSkillRank(SKILL_OPEN_LOCK) - GetAbilityModifier(ABILITY_DEXTERITY); + + if(GetIsObjectValid(oLastObject) && GetPlotFlag(oLastObject) == FALSE) + { + if(GetIsDoorActionPossible(oLastObject, DOOR_ACTION_KNOCK) || GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_KNOCK)) + { + ClarAllActions(); + VoiceCanDo(); + ActionCastSpellAtObject(SPELL_KNOCK, oLastObject); + ActionWait(1.0); + bValid = FALSE; + } + else if (GetIsDoorActionPossible(oLastObject, DOOR_ACTION_UNLOCK)|| GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_UNLOCK)) + { + ClarAllActions(); + VoicePicklock(); + ActionWait(1.0); + ActionUseSkill(SKILL_OPEN_LOCK,oLastObject); + bValid = FALSE; + } + else if(nSkill < 5 && GetAbilityScore(OBJECT_SELF, ABILITY_STRENGTH) >= 16 && GetSkillRank(SKILL_OPEN_LOCK) <= 0) + { + if(GetIsDoorActionPossible(oLastObject, DOOR_ACTION_BASH) || GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_BASH)) + { + ClarAllActions(); + VoiceCanDo(); + ActionEquipMostDamagingMelee(oLastObject); + WrapperActionAttack(oLastObject); + SetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH", oLastObject); + bValid = FALSE; + } + } + if(bValid == TRUE) + { + //ClarAllActions(); + VoiceCannotDo(); + } + else + { + ActionDoCommand(VoiceTaskComplete()); + } + } + } + } + } + break; + + case ASSOCIATE_COMMAND_MASTERUNDERATTACK: //Check whether the master has you in AGGRESSIVE DEFEND MODE + { + if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + //Check the henchmens current target + object oTarget = GetAttemptedAttackTarget(); + if(!GetIsObjectValid(oTarget)) + { + oTarget = GetAttemptedSpellTarget(); + if(!GetIsObjectValid(oTarget)) + { + if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER)) + { + DetermineCombatRound(GetLastHostileActor(GetMaster())); + } + else + { + DetermineCombatRound(); + } + } + } + //Switch targets only if the target is not attacking the master and is greater than 6.0 from + //the master. + if(GetAttackTarget(oTarget) != GetMaster() && GetDistanceBetween(oTarget, GetMaster()) > 6.0) + { + if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER) && GetIsObjectValid(GetLastHostileActor(GetMaster()))) + { + DetermineCombatRound(GetLastHostileActor(GetMaster())); + } + } + } + } + break; + + case ASSOCIATE_COMMAND_STANDGROUND: //No longer follow the master or guard him + { + SetAssociateState(NW_ASC_MODE_STAND_GROUND); + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE); + DelayCommand(2.0, VoiceCanDo()); + WrapperActionAttack(OBJECT_INVALID); + ClarAllActions(); + } + break; + + case ASSOCIATE_COMMAND_MASTERSAWTRAP: + { + int nCheck = 0; + if(!GetIsInCombat()) + { + if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + object oTrap = GetLastTrapDetected(); + if(GetIsObjectValid(oTrap)) + { + int nTrapDC = GetTrapDisarmDC(oTrap); + int nSkill = GetSkillRank(SKILL_DISABLE_TRAP); + int nMod = GetAbilityModifier(ABILITY_DEXTERITY); + if((nSkill - nMod) > 0) + { + nSkill = nSkill + 20 - nTrapDC; + } + else + { + nSkill = 0; + nCheck = 1; + } + + if(GetCurrentAction(OBJECT_SELF) != ACTION_DISABLETRAP && nSkill > 0) + { + VoiceStop(); + if(GetHasSkill(SKILL_DISABLE_TRAP, OBJECT_SELF)) + { + ClarAllActions(); + ActionUseSkill(SKILL_DISABLE_TRAP, oTrap); + ActionDoCommand(SetCommandable(TRUE)); + ActionDoCommand(VoiceTaskComplete()); + SetCommandable(FALSE); + nCheck = 2; + } + } + else if(nCheck = 0 && + GetSkillRank(SKILL_DISABLE_TRAP) > 0 && + GetCurrentAction(OBJECT_SELF) != ACTION_DISABLETRAP) + { + VoiceCannotDo(); + } + } + } + } + } + break; + + case ASSOCIATE_COMMAND_MASTERATTACKEDOTHER: + { + if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + if(!GetAssociateState(NW_ASC_MODE_DEFEND_MASTER)) + { + if(!GetIsFighting(OBJECT_SELF)) + { + object oAttack = GetAttackTarget(GetMaster()); + if(GetIsObjectValid(oAttack) && GetObjectSeen(oAttack)) + { + ClarAllActions(); + DetermineCombatRound(oAttack); + } + } + } + } + } + break; + + case ASSOCIATE_COMMAND_MASTERGOINGTOBEATTACKED: + { + if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)) + { + if(!GetIsFighting(OBJECT_SELF)) + { + object oAttacker = GetGoingToBeAttackedBy(GetMaster()); + if(GetIsObjectValid(oAttacker) && GetObjectSeen(oAttacker)) + { + ClarAllActions(); + DetermineCombatRound(oAttacker); + } + } + } + } + break; + + case ASSOCIATE_COMMAND_LEAVEPARTY: + { + object oMaster = GetMaster(); + if(GetIsObjectValid(oMaster)) + { + ClarAllActions(); + if(GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster()) == OBJECT_SELF) + { + AddJournalQuestEntry("Henchman",50,GetMaster(),FALSE,FALSE,TRUE); + } + SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", oMaster); + RemoveHenchman(oMaster, OBJECT_SELF); + } + + } + break; */ + } +} + +//:://///////////////////////////////////////////// +//:: Set and Get NPC Warning Status +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This function sets a local int on OBJECT_SELF + which will be checked in the On Attack, On + Damaged and On Disturbed scripts to check if + the offending party was a PC and was friendly. + The Get will return the status of the local. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 29, 2001 +//::////////////////////////////////////////////// + +// NPCs who have warning status set to TRUE will allow +// one 'free' attack by PCs from a non-hostile faction. +void SetNPCWarningStatus(int nStatus = TRUE) +{ + SetLocalInt(OBJECT_SELF, "NW_GENERIC_WARNING_STATUS", nStatus); +} + +// NPCs who have warning status set to TRUE will allow +// one 'free' attack by PCs from a non-hostile faction. +int GetNPCWarningStatus() +{ + return GetLocalInt(OBJECT_SELF, "NW_GENERIC_WARNING_STATUS"); +} + +//:://///////////////////////////////////////////// +//:: Set SummonHelpIfAttacked +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + This function works in tandem with an encounter + to spawn in guards to fight for the attacked + NPC. MAKE SURE THE ENCOUNTER TAG IS SET TO: + + "ENC_" + NPC TAG +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 29, 2001 +//::////////////////////////////////////////////// + +//Presently Does not work with the current implementation of encounter trigger +void SetSummonHelpIfAttacked() +{ + string sEncounter = "ENC_" + GetTag(OBJECT_SELF); + object oTrigger = GetObjectByTag(sEncounter); + + if(GetIsObjectValid(oTrigger)) + { + SetEncounterActive(TRUE, oTrigger); + } +} + +//************************************************************************************************************************************ +//************************************************************************************************************************************ +// +// ESCAPE FUNCTIONS +// +//************************************************************************************************************************************ +//************************************************************************************************************************************ + +//:://///////////////////////////////////////////// +//:: Set, Get Activate,Flee to Exit +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + The target object flees to the specified + way point and then destroys itself, to be + respawned at a later point. For unkillable + sign post characters who are not meant to fight + back. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 29, 2001 +//::////////////////////////////////////////////// + +//This function is used only because ActionDoCommand can only accept void functions +void CreateSignPostNPC(string sTag, location lLocal) +{ + CreateObject(OBJECT_TYPE_CREATURE, sTag, lLocal); +} + +void ActivateFleeToExit() +{ + object oExitWay = GetWaypointByTag("EXIT_" + GetTag(OBJECT_SELF)); + int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER"); + location lLocal = GetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT"); + float fDelay = 6.0; + string sTag = GetTag(OBJECT_SELF); + + if(nPlot & NW_FLAG_TELEPORT_RETURN || nPlot & NW_FLAG_TELEPORT_LEAVE) + { + effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF); + if(nPlot & NW_FLAG_TELEPORT_RETURN) + { + DelayCommand(fDelay, ActionDoCommand(CreateSignPostNPC(sTag, lLocal))); + } + ActionDoCommand(DestroyObject(OBJECT_SELF, 0.75)); + } + else + { + if(nPlot & NW_FLAG_ESCAPE_LEAVE) + { + ActionMoveToObject(oExitWay, TRUE); + ActionDoCommand(DestroyObject(OBJECT_SELF, 1.0)); + } + else if(nPlot & NW_FLAG_ESCAPE_RETURN) + { + ActionMoveToObject(oExitWay, TRUE); + DelayCommand(fDelay, ActionDoCommand(CreateSignPostNPC(sTag, lLocal))); + ActionDoCommand(DestroyObject(OBJECT_SELF, 1.0)); + } + } +} + +int GetFleeToExit() +{ + int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER"); + if(nPlot & NW_FLAG_ESCAPE_RETURN) + { + return TRUE; + } + else if(nPlot & NW_FLAG_ESCAPE_LEAVE) + { + return TRUE; + } + else if(nPlot & NW_FLAG_TELEPORT_RETURN) + { + return TRUE; + } + else if(nPlot & NW_FLAG_TELEPORT_LEAVE) + { + return TRUE; + } + return FALSE; +} + + + +//********************************** +//********************************** +//********************************** +// PRIVATE FUNCTIONS +//********************************** +//********************************** +//********************************** + +//This is experimental and has not been looked at closely. +void ExitAOESpellArea(object oAOEObject) +{ + ClearActions(CLEAR_NW_I0_GENERIC_ExitAOESpellArea); + ActionMoveAwayFromObject(oAOEObject, TRUE, 5.0); + AssignCommand(OBJECT_SELF, DetermineCombatRound()); +} + + +//:://///////////////////////////////////////////// +//:: Get Character Levels +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Returns the combined class levels of the + target. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 22, 2001 +//::////////////////////////////////////////////// + +int GetCharacterLevel(object oTarget) +{ + return GetHitDice(oTarget); +} + + + + +//:://///////////////////////////////////////////// +//:: Remove Ambient Sleep +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Checks if the NPC has sleep on them because + of ambient animations. Sleeping creatures + must make a DC 15 listen check. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Feb 27, 2002 +//::////////////////////////////////////////////// + +void RemoveAmbientSleep() +{ + if(GetHasEffect(EFFECT_TYPE_SLEEP)) + { + effect eSleep = GetFirstEffect(OBJECT_SELF); + while(GetIsEffectValid(eSleep)) + { + if(GetEffectCreator(eSleep) == OBJECT_SELF) + { + int nRoll = d20(); + nRoll += GetSkillRank(SKILL_LISTEN); + nRoll += GetAbilityModifier(ABILITY_WISDOM); + if(nRoll > 15) + { + RemoveEffect(OBJECT_SELF, eSleep); + } + } + eSleep = GetNextEffect(OBJECT_SELF); + } + } +} + + +//:://///////////////////////////////////////////// +//:: Get Locked Object +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Finds the closest locked object to the object + passed in up to a maximum of 10 objects. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: March 15, 2002 +//::////////////////////////////////////////////// + +object GetLockedObject(object oMaster) +{ + int nCnt = 1; + int bValid = TRUE; + object oLastObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetLocation(oMaster), nCnt); + while (GetIsObjectValid(oLastObject) && bValid == TRUE) + { + //COMMENT THIS BACK IN WHEN DOOR ACTION WORKS ON PLACABLE. + + //object oItem = GetFirstItemInInventory(oLastObject); + if(GetLocked(oLastObject)) + { + return oLastObject; + } + nCnt++; + if(nCnt == 10) + { + bValid = FALSE; + } + oLastObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetLocation(oMaster), nCnt); + } + return OBJECT_INVALID; +} + + + + + +//:://///////////////////////////////////////////// +//:: Check if an item is locked +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Checks that an item was unlocked. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +//::////////////////////////////////////////////// + +void CheckIsUnlocked(object oLastObject) +{ + if(GetLocked(oLastObject)) + { + ActionDoCommand(VoiceCuss()); + } + else + { + ActionDoCommand(VoiceCanDo()); + } +} + + +//:://///////////////////////////////////////////// +//:: Play Mobile Ambient Animations +//:: This function is now just a wrapper around +//:: code from x0_i0_anims. +//::////////////////////////////////////////////// +void PlayMobileAmbientAnimations() +{ + if(!GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)) { + // not a bird + PlayMobileAmbientAnimations_NonAvian(); + } else { + // a bird + PlayMobileAmbientAnimations_Avian(); + } +} + +//:://///////////////////////////////////////////// +//:: Determine Special Behavior +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Determines the special behavior used by the NPC. + Generally all NPCs who you want to behave differently + than the defualt behavior. + For these behaviors, passing in a valid object will + cause the creature to become hostile the the attacker. + + MODIFIED February 7 2003: + - Rearranged logic order a little so that the creatures + will actually randomwalk when not fighting +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Dec 14, 2001 +//::////////////////////////////////////////////// + +void DetermineSpecialBehavior(object oIntruder = OBJECT_INVALID) +{ + object oTarget = GetNearestSeenEnemy(); + if(GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE)) + { + int bAttack = FALSE; + if(!GetIsObjectValid(oIntruder)) + { + if(!GetIsObjectValid(GetAttemptedAttackTarget()) && + !GetIsObjectValid(GetAttemptedSpellTarget()) && + !GetIsObjectValid(GetAttackTarget())) + { + if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 8.0) + { + if(!GetIsFriend(oTarget)) + { + if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0) + { + SetIsTemporaryEnemy(oTarget, OBJECT_SELF, FALSE, 20.0); + bAttack = TRUE; + DetermineCombatRound(oTarget); + } + } + } + } + } + else if(!IsInConversation(OBJECT_SELF)) + { + bAttack = TRUE; + DetermineCombatRound(oIntruder); + } + + // * if not attacking, the wander + if (bAttack == FALSE) + { + ClearActions(CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior1); + ActionRandomWalk(); + return; + } + } + else if(GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE)) + { + if(!GetIsObjectValid(GetAttemptedAttackTarget()) && + !GetIsObjectValid(GetAttemptedSpellTarget()) && + !GetIsObjectValid(GetAttackTarget())) + { + if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 6.0) + { + if(!GetIsFriend(oTarget)) + { + if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0) + { + TalentFlee(oTarget); + } + } + } + } + else if(!IsInConversation(OBJECT_SELF)) + { + ClearActions(CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior2); + ActionRandomWalk(); + return; + } + } +} + +//:://///////////////////////////////////////////// +//:: Bash Doors +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Used in DetermineCombatRound to keep a + henchmen bashing doors. +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 4, 2002 +//::////////////////////////////////////////////// + +int BashDoorCheck(object oIntruder = OBJECT_INVALID) +{ + int bDoor = FALSE; + //This code is here to make sure that henchmen keep bashing doors and placables. + object oDoor = GetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH"); + + // * MODIFICATION February 7 2003 BK + // * don't bash trapped doors. + if (GetIsTrapped(oDoor) ) return FALSE; + + if(GetIsObjectValid(oDoor)) + { + int nDoorMax = GetMaxHitPoints(oDoor); + int nDoorNow = GetCurrentHitPoints(oDoor); + int nCnt = GetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP"); + if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)) + || (!GetIsObjectValid(oIntruder) && !GetIsObjectValid(GetMaster()))) + { + if(GetLocked(oDoor)) + { + if(nDoorMax == nDoorNow) + { + nCnt++; + SetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP", nCnt); + } + if(nCnt <= 0) + { + bDoor = TRUE; + if(GetHasFeat(FEAT_IMPROVED_POWER_ATTACK)) + { + ActionUseFeat(FEAT_IMPROVED_POWER_ATTACK, oDoor); + } + else if(GetHasFeat(FEAT_POWER_ATTACK)) + { + ActionUseFeat(FEAT_POWER_ATTACK, oDoor); + } + else + { + WrapperActionAttack(oDoor); + } + } + } + } + if(bDoor == FALSE) + { + VoiceCuss(); + DeleteLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH"); + DeleteLocalInt(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH_HP"); + } + } + return bDoor; +} + +//:://///////////////////////////////////////////// +//:: Determine Class to Use +//:: Copyright (c) 2002 Bioware Corp. +//::////////////////////////////////////////////// +/* + Determines which of a NPCs three classes to + use in DetermineCombatRound +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: April 4, 2002 +//::////////////////////////////////////////////// + +int DetermineClassToUse() +{ + int nClass; + int nTotal = GetHitDice(OBJECT_SELF); + float fTotal = IntToFloat(nTotal); + + int nState1 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(1))) / fTotal) * 100); + // MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(1)) + " %" + IntToString(nState1)); + + int nState2 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(2))) / fTotal) * 100) + nState1; + // MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(2)) + " %" + IntToString(nState2)); + + int nState3 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(3))) / fTotal) * 100) + nState2; + // MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(3)) + " %" + IntToString(nState3)); + + int nUseClass = d100(); + // MyPrintString("D100 Roll " + IntToString(nUseClass)); + + if(nUseClass <= nState1) + { + nClass = GetClassByPosition(1); + } + else if(nUseClass > nState1 && nUseClass <= nState2) + { + nClass = GetClassByPosition(2); + } + else + { + nClass = GetClassByPosition(3); + } + // MyPrintString(GetName(OBJECT_SELF) + " Return Class = " + IntToString(nClass)); + + return nClass; +} + + + +/* DO NOT CLOSE THIS TOP COMMENT! + This main() function is here only for compilation testing. +void main() {} +/* */ diff --git a/src/_removed/nw_s0_heal.ncs b/src/_removed/nw_s0_heal.ncs new file mode 100644 index 0000000000000000000000000000000000000000..a29c438fdc9bb51b76fa835c5a4a82b9e0d69223 GIT binary patch literal 2088 zcmbVNO-~b16n!)EKtu#YYluc2KVlR_L5#))lCg}mp&zClKUlpKiqHrni5SrpiT(n9 zfr%U4`y*V`goP%WG|`0%V_2|YL9`L?J9nnEO$iDOubunuIq%$a@64p4S^Mt5#r~T@ zw46IG=&!{VvPm5FpQ_2++?)76+{^U#|H!Yhr zOOp_T=2kqJTda+Dr0%JNin%EjS0izEgi<5-`&B%vqIWVGH{~V9RV<#tMi*@)oUEsk zw741NIir-`sz%e^SUizHPMgZOS&fW(xb7ef*t2S6Jf6~k{a3Fel=ad9ZxBd1Nmo^( z?a7!*rbk@mc%Bm->k)9JvsWAyo12?OTbFi8n4R>o!jF`?=AG8zCCagosn-c2de^iQ z2DIcnl`CGDoKqEAHUVxoEv^Jx@5u{{f%eY$!Uu?-3?{ib!_eBl2?cJ?Gqgt(jHIFS8@1PzbiD4&qGl775-~<7(g&OK6~x3al!^tn^g( z$9%0jD0-0)p%bMajopTTH6ah3#;Q~`H8>VFq>$)w1VWoK?Hbd~^_!aQw;DoRX4taTCM!$#Va=u-7Z0Da9 z{AoOchPYid1G$0Yl2{$OW9b!ymskMyA1!PVh%(pGfPnRudB%e>p=^o9A@KMH^kU|X zVS^0mF>uG&4P=!e=q1)XWF4fJrIXF3qjAS`gSQ|E`K}x^LpQ=;D<1Zunw_Q(3c2XB SthPZ-e0nqI+WgWh+u|=bmid4H literal 0 HcmV?d00001 diff --git a/src/_removed/nw_s0_heal.nss b/src/_removed/nw_s0_heal.nss new file mode 100644 index 0000000..00ca470 --- /dev/null +++ b/src/_removed/nw_s0_heal.nss @@ -0,0 +1,74 @@ +//:://///////////////////////////////////////////// +//:: Heal +//:: [NW_S0_Heal.nss] +//:: Copyright (c) 2000 Bioware Corp. +//::////////////////////////////////////////////// +//:: Heals the target to full unless they are undead. +//:: If undead they reduced to 1d4 HP. +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Jan 12, 2001 +//:: Modified 69MEH69 JUL2003 +//::////////////////////////////////////////////// +//:: Update Pass By: Preston W, On: Aug 1, 2001 +#include "69_i0_henchman" +#include "NW_I0_SPELLS" +void main() +{ + //Declare major variables + object oTarget = GetSpellTargetObject(); + effect eKill, eHeal; + int nDamage, nHeal, nModify, nMetaMagic, nTouch; + effect eSun = EffectVisualEffect(VFX_IMP_SUNSTRIKE); + effect eHealVis = EffectVisualEffect(VFX_IMP_HEALING_X); + string sTag = GetTag(oTarget); + object oArea = GetArea(oTarget); + //Check to see if the target is an undead + if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) + { + if(!GetIsReactionTypeFriendly(oTarget)) + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEAL)); + //Make a touch attack + if (TouchAttackMelee(oTarget)) + { + //Make SR check + if (!MyResistSpell(OBJECT_SELF, oTarget)) + { + //Roll damage + nModify = d4(); + nMetaMagic = GetMetaMagicFeat(); + //Make metamagic check + if (nMetaMagic == METAMAGIC_MAXIMIZE) + { + nModify = 1; + } + //Figure out the amount of damage to inflict + nDamage = GetCurrentHitPoints(oTarget) - nModify; + //Set damage + eKill = EffectDamage(nDamage, DAMAGE_TYPE_POSITIVE); + //Apply damage effect and VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eSun, oTarget); + } + } + } + } + else + { + //Fire cast spell at event for the specified target + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_HEAL, FALSE)); + //Figure out how much to heal + nHeal = GetMaxHitPoints(oTarget); + //Set the heal effect + eHeal = EffectHeal(nHeal); + //Apply the heal effect and the VFX impact + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHealVis, oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + if(GetIsHenchmanDying(oTarget)) + { + SetLocalInt(oArea, "nCHP" +sTag, 21); + } + } +} diff --git a/src/include/inc_epicspelldef.nss b/src/include/inc_epicspelldef.nss index 78b89b4..613b0f1 100644 --- a/src/include/inc_epicspelldef.nss +++ b/src/include/inc_epicspelldef.nss @@ -47,77 +47,78 @@ const string MES_CONTINGENCIES_YES2 = "The contingencies must expire to allo */ //Primogenitors SpellID constants -const int SPELL_EPIC_A_STONE = 0;//4007; -const int SPELL_EPIC_ACHHEEL = 1;//4000; -const int SPELL_EPIC_AL_MART = 2;//4002; -const int SPELL_EPIC_ALLHOPE = 3;//4001; -const int SPELL_EPIC_ANARCHY = 4;//4003; -const int SPELL_EPIC_ANBLAST = 5;//4004; -const int SPELL_EPIC_ANBLIZZ = 6;//4005; -const int SPELL_EPIC_ARMY_UN = 7;//4006; -const int SPELL_EPIC_BATTLEB = 999;//4008; -const int SPELL_EPIC_CELCOUN = 8;//4009; -const int SPELL_EPIC_CHAMP_V = 9;//4010; -const int SPELL_EPIC_CON_RES =10;//4011; -const int SPELL_EPIC_CON_REU =11;//4012; -const int SPELL_EPIC_DEADEYE =12;//4013; -const int SPELL_EPIC_DIREWIN =13;//4015; -const int SPELL_EPIC_DREAMSC =14;//4017; -const int SPELL_EPIC_DRG_KNI =15;//4016; -const int SPELL_EPIC_DTHMARK =1000;//4014; -const int SPELL_EPIC_DULBLAD =16;//4018; -const int SPELL_EPIC_DWEO_TH =17;//4019; -const int SPELL_EPIC_ENSLAVE =18;//4020; -const int SPELL_EPIC_EP_M_AR =19;//4021; -const int SPELL_EPIC_EP_RPLS =20;//4022; -const int SPELL_EPIC_EP_SP_R =21;//4023; -const int SPELL_EPIC_EP_WARD =22;//4024; -const int SPELL_EPIC_ET_FREE =23;//4025; -const int SPELL_EPIC_FIEND_W =24;//4026; -const int SPELL_EPIC_FLEETNS =25;//4027; -const int SPELL_EPIC_GEMCAGE =26;//4028; -const int SPELL_EPIC_GODSMIT =27;//4029; -const int SPELL_EPIC_GR_RUIN =28;//4030; -const int SPELL_EPIC_GR_SP_RE=29;//4031; -const int SPELL_EPIC_GR_TIME =30;//4032; -const int SPELL_EPIC_HELBALL =31;//4034; -const int SPELL_EPIC_HELSEND =1001;//4033; -const int SPELL_EPIC_HERCALL =32;//4035; -const int SPELL_EPIC_HERCEMP =33;//4036; -const int SPELL_EPIC_IMPENET =34;//4037; -const int SPELL_EPIC_LEECH_F =35;//4038; -const int SPELL_EPIC_LEG_ART =1002;//4039; -const int SPELL_EPIC_LIFE_FT =1003;//4040; -const int SPELL_EPIC_MAGMA_B =36;//4041; -const int SPELL_EPIC_MASSPEN =37;//4042; -const int SPELL_EPIC_MORI = 38;//4043; -const int SPELL_EPIC_MUMDUST =39;//4044; -const int SPELL_EPIC_NAILSKY =40;//4045; -const int SPELL_EPIC_NIGHTSU =1004;//4046; -const int SPELL_EPIC_ORDER_R =41;//4047; -const int SPELL_EPIC_PATHS_B =42;//4048; -const int SPELL_EPIC_PEERPEN =43;//4049; -const int SPELL_EPIC_PESTIL = 44;//4050; -const int SPELL_EPIC_PIOUS_P =45;//4051; -const int SPELL_EPIC_PLANCEL =46;//4052; -const int SPELL_EPIC_PSION_S =47;//4053; -const int SPELL_EPIC_RAINFIR =48;//4054; -const int SPELL_EPIC_RISEN_R =1005;//4055; -const int SPELL_EPIC_RUINN = 49;//4056; //NON_STANDARD -const int SPELL_EPIC_SINGSUN =50;//4057; -const int SPELL_EPIC_SP_WORM =51;//4058; -const int SPELL_EPIC_STORM_M =52;//4059; -const int SPELL_EPIC_SUMABER =53;//4060; -const int SPELL_EPIC_SUP_DIS =54;//4061; -const int SPELL_EPIC_SYMRUST =1006;//4062; -const int SPELL_EPIC_THEWITH =55;//4063; -const int SPELL_EPIC_TOLO_KW =56;//4064; -const int SPELL_EPIC_TRANVIT =57;//4065; -const int SPELL_EPIC_TWINF = 58;//4066; -const int SPELL_EPIC_UNHOLYD =59;//4067; -const int SPELL_EPIC_UNIMPIN =60;//4068; -const int SPELL_EPIC_UNSEENW =61;//4069; -const int SPELL_EPIC_WHIP_SH =62;//4070; +const int SPELL_EPIC_A_STONE = 0;//4007; +const int SPELL_EPIC_ACHHEEL = 1;//4000; +const int SPELL_EPIC_AL_MART = 2;//4002; +const int SPELL_EPIC_ALLHOPE = 3;//4001; +const int SPELL_EPIC_ANARCHY = 4;//4003; +const int SPELL_EPIC_ANBLAST = 5;//4004; +const int SPELL_EPIC_ANBLIZZ = 6;//4005; +const int SPELL_EPIC_ARMY_UN = 7;//4006; +const int SPELL_EPIC_BATTLEB = 999;//4008; +const int SPELL_EPIC_CELCOUN = 8;//4009; +const int SPELL_EPIC_CHAMP_V = 9;//4010; +const int SPELL_EPIC_CON_RES = 10;//4011; +const int SPELL_EPIC_CON_REU = 11;//4012; +const int SPELL_EPIC_DEADEYE = 12;//4013; +const int SPELL_EPIC_DIREWIN = 13;//4015; +const int SPELL_EPIC_DREAMSC = 14;//4017; +const int SPELL_EPIC_DRG_KNI = 15;//4016; +const int SPELL_EPIC_DTHMARK = 1000;//4014; +const int SPELL_EPIC_DULBLAD = 16;//4018; +const int SPELL_EPIC_DWEO_TH = 17;//4019; +const int SPELL_EPIC_ENSLAVE = 18;//4020; +const int SPELL_EPIC_EP_M_AR = 19;//4021; +const int SPELL_EPIC_EP_RPLS = 20;//4022; +const int SPELL_EPIC_EP_SP_R = 21;//4023; +const int SPELL_EPIC_EP_WARD = 22;//4024; +const int SPELL_EPIC_ET_FREE = 23;//4025; +const int SPELL_EPIC_FIEND_W = 24;//4026; +const int SPELL_EPIC_FLEETNS = 25;//4027; +const int SPELL_EPIC_GEMCAGE = 26;//4028; +const int SPELL_EPIC_GODSMIT = 27;//4029; +const int SPELL_EPIC_GR_RUIN = 28;//4030; +const int SPELL_EPIC_GR_SP_RE = 29;//4031; +const int SPELL_EPIC_GR_TIME = 30;//4032; +const int SPELL_EPIC_HELBALL = 31;//4034; +const int SPELL_EPIC_HELSEND = 1001;//4033; +const int SPELL_EPIC_HERCALL = 32;//4035; +const int SPELL_EPIC_HERCEMP = 33;//4036; +const int SPELL_EPIC_IMPENET = 34;//4037; +const int SPELL_EPIC_LEECH_F = 35;//4038; +const int SPELL_EPIC_LEG_ART = 1002;//4039; +const int SPELL_EPIC_LIFE_FT = 1003;//4040; +const int SPELL_EPIC_MAGMA_B = 36;//4041; +const int SPELL_EPIC_MASSPEN = 37;//4042; +const int SPELL_EPIC_MORI = 38;//4043; +const int SPELL_EPIC_MUMDUST = 39;//4044; +const int SPELL_EPIC_NAILSKY = 40;//4045; +const int SPELL_EPIC_NIGHTSU = 1004;//4046; +const int SPELL_EPIC_ORDER_R = 41;//4047; +const int SPELL_EPIC_PATHS_B = 42;//4048; +const int SPELL_EPIC_PEERPEN = 43;//4049; +const int SPELL_EPIC_PESTIL = 44;//4050; +const int SPELL_EPIC_PIOUS_P = 45;//4051; +const int SPELL_EPIC_PLANCEL = 46;//4052; +const int SPELL_EPIC_PSION_S = 47;//4053; +const int SPELL_EPIC_RAINFIR = 48;//4054; +//const int SPELL_EPIC_RISEN_R =1005;//4055; +const int SPELL_EPIC_RISEN_R = 49;//4055; +const int SPELL_EPIC_RUINN = 50;//4056; //NON_STANDARD +const int SPELL_EPIC_SINGSUN = 51;//4057; +const int SPELL_EPIC_SP_WORM = 52;//4058; +const int SPELL_EPIC_STORM_M = 53;//4059; +const int SPELL_EPIC_SUMABER = 54;//4060; +const int SPELL_EPIC_SUP_DIS = 55;//4061; +const int SPELL_EPIC_SYMRUST = 1006;//4062; +const int SPELL_EPIC_THEWITH = 56;//4063; +const int SPELL_EPIC_TOLO_KW = 57;//4064; +const int SPELL_EPIC_TRANVIT = 58;//4065; +const int SPELL_EPIC_TWINF = 59;//4066; +const int SPELL_EPIC_UNHOLYD = 60;//4067; +const int SPELL_EPIC_UNIMPIN = 61;//4068; +const int SPELL_EPIC_UNSEENW = 62;//4069; +const int SPELL_EPIC_WHIP_SH = 63;//4070; /* diff --git a/src/include/inc_epicspellfnc.nss b/src/include/inc_epicspellfnc.nss index 59f4dd6..7fb6054 100644 --- a/src/include/inc_epicspellfnc.nss +++ b/src/include/inc_epicspellfnc.nss @@ -246,7 +246,7 @@ int GetSpellFromAbrev(string sAbrev) sAbrev = GetStringLowerCase(sAbrev); if(GetStringLeft(sAbrev, 8) == "epic_sp_") sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8); - if(DEBUG) DoDebug("sAbrew to check vs: " + sAbrev); + if(DEBUG) DoDebug("sAbrev to check vs: " + sAbrev); int i = 0; string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i)); while(sLabel != "") diff --git a/src/include/inc_infusion.nss b/src/include/inc_infusion.nss new file mode 100644 index 0000000..e9c7528 --- /dev/null +++ b/src/include/inc_infusion.nss @@ -0,0 +1,481 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//:://///////////////////////////////////////////// +//:: +/* + Script: inc_infusion + Author: Jaysyn + Created: 2025-08-11 17:01:26 + + Description: + Contains most functions related to the Create + Infusion feat. + +*/ +//:: +//::////////////////////////////////////////////// +#include "prc_inc_spells" + +int GetMaxDivineSpellLevel(object oCaster, int nClass); +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID); +int GetIsClassSpell(object oCaster, int nSpellID, int nClass); +int GetHasSpellOnClassList(object oCaster, int nSpellID); +void InfusionSecondSave(object oUser, int nDC); + +/** + * @brief Finds the class index for which the given spell is available to the specified caster. + * + * This function iterates through all possible classes and returns the first class + * index for which the specified spell is on the caster's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to find the class for. + * + * @return The class index that has the spell on its class spell list for the caster, + * or -1 if no matching class is found. + */ +int FindSpellCastingClass(object oCaster, int nSpellID) +{ + int i = 0; + int nClassFound = -1; + int nClass; + + // Only loop through caster's classes + for (i = 0; i <= 8; i++) + { + nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + nClassFound = nClass; + break; + } + } + + return nClassFound; +} + + +/** + * @brief Performs validation checks to determine if the caster can use a spell infusion from the specified item. + * + * This function verifies that the item is a valid infused herb, checks the caster's relevant class and ability scores, + * confirms the caster is a divine spellcaster with the necessary caster level, and ensures the spell is on the caster's class spell list. + * + * @param oCaster The creature attempting to use the infusion. + * @param oItem The infused herb item containing the spell. + * @param nSpellID The spell ID of the infusion spell being cast. + * + * @return TRUE if all infusion use checks pass and the caster can use the infusion; FALSE otherwise. + */ + int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // **CRITICAL: Find the correct class that actually has the spell on its list** + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: " + IntToString(nClassCaster) + "."); + + // Check for valid class + if (nClassCaster == -1) + { + FloatingTextStringOnCreature("No valid class found for this spell.", oCaster); + return FALSE; + } + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list - (This will also double-check via the class) + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + +/* int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID) +{ + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + + if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster); + return FALSE; + + } + + int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID); + if (bPnPHerbs && nItemSpellLvl == -1) + { + FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster); + return FALSE; + } + + // Find relevant class for the spell + int nClassCaster = FindSpellCastingClass(oCaster, nSpellID); + + if(DEBUG) DoDebug("nClassCaster is: "+IntToString(nClassCaster)+"."); + + if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 ) + { + FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster); + return FALSE; + } + + // Must have spell on class list + if (!GetHasSpellOnClassList(oCaster, nSpellID)) + { + FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster); + return FALSE; + } + + // Must meet ability requirement: Ability score >= 10 + spell level + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster); + int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+"."); + + if (nClassAbility < 10 + nSpellLevel) + { + FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster); + return FALSE; + } + + // Must have a divine caster level at least equal to infusion's caster level + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+"."); + + if (nDivineLvl < nItemSpellLvl) + { + FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster); + return FALSE; + } + + return TRUE; +} + */ +/** + * @brief Retrieves the maximum divine spell level known by the caster for a given class. + * + * This function checks the caster's local integers named "PRC_DivSpell1" through "PRC_DivSpell9" + * in descending order to determine the highest divine spell level available. + * It returns the highest spell level for which the corresponding local int is false (zero). + * + * @param oCaster The creature whose divine spell levels are being checked. + * @param nClass The class index for which to check the divine spell level (currently unused). + * + * @return The highest divine spell level known by the caster (1 to 9). + */ +int GetMaxDivineSpellLevel(object oCaster, int nClass) +{ + int i = 9; + for (i; i > 0; i--) + { + if(!GetLocalInt(oCaster, "PRC_DivSpell"+IntToString(i))) + return i; + } + return 1; +} + +/** + * @brief Retrieves the spell school of an herb based on its resref by looking it up in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the corresponding spell school as an integer constant. + * If not found or the SpellSchool column is missing/invalid, it returns -1. + * + * @param oHerb The herb object to check. + * + * @return The spell school constant corresponding to the herb's infusion spell school, + * or -1 if the herb is invalid, not found, or the data is missing. + */ +int GetHerbsSpellSchool(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; + if (sRowResref == sResref) + { + string sHerbSpellSchool = Get2DAString("craft_infusion", "SpellSchool", nRow); + + if (sHerbSpellSchool == "A") return SPELL_SCHOOL_ABJURATION; + else if (sHerbSpellSchool == "C") return SPELL_SCHOOL_CONJURATION; + else if (sHerbSpellSchool == "D") return SPELL_SCHOOL_DIVINATION; + else if (sHerbSpellSchool == "E") return SPELL_SCHOOL_ENCHANTMENT; + else if (sHerbSpellSchool == "V") return SPELL_SCHOOL_EVOCATION; + else if (sHerbSpellSchool == "I") return SPELL_SCHOOL_ILLUSION; + else if (sHerbSpellSchool == "N") return SPELL_SCHOOL_NECROMANCY; + else if (sHerbSpellSchool == "T") return SPELL_SCHOOL_TRANSMUTATION; + else return SPELL_SCHOOL_GENERAL; + + return -1; + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the infusion spell level of an herb by matching its resref in the craft_infusion.2da file. + * + * This function searches the "craft_infusion" 2DA for a row matching the herb's resref. + * If found, it returns the spell level from the SpellLevel column as an integer. + * If not found or the column is missing, it returns -1. + * + * @param oHerb The herb object whose infusion spell level is to be retrieved. + * + * @return The spell level as an integer if found, or -1 if the herb is invalid, not found, or the column is missing. + */ +int GetHerbsInfusionSpellLevel(object oHerb) +{ + if (!GetIsObjectValid(oHerb)) return -1; + + string sResref = GetResRef(oHerb); + int nRow = 0; + string sRowResref; + + // Brute-force loop — adjust limit if your 2DA has more than 500 rows + while (nRow < 200) + { + sRowResref = Get2DACache("craft_infusion", "Resref", nRow); + if (sRowResref == "") break; // End of valid rows + if (sRowResref == sResref) + { + string sSpellLevelStr = Get2DAString("craft_infusion", "SpellLevel", nRow); + return StringToInt(sSpellLevelStr); + } + nRow++; + } + return -1; // Not found +} + +/** + * @brief Retrieves the caster level of a specific cast-spell item property from an item. + * + * This function iterates through the item properties of the given item, searching for an + * ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL property that matches the specified spell ID. + * If found, it returns the caster level value stored in the item property. + * + * @param oItem The item object to check. + * @param nSpellID The spell ID to match against the item property. + * + * @return The caster level associated with the matching cast-spell item property, + * or -1 if no matching property is found. + */ +int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID) +{ + int nFoundCL = -1; + + itemproperty ip = GetFirstItemProperty(oItem); + while (GetIsItemPropertyValid(ip)) + { + int nType = GetItemPropertyType(ip); + + // First preference: PRC's CASTER_LEVEL itemprop + if (nType == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + return GetItemPropertyCostTableValue(ip); // Found exact CL + } + } + + // Fallback: vanilla CAST_SPELL property + if (nType == ITEM_PROPERTY_CAST_SPELL && nFoundCL == -1) + { + int nSubType = GetItemPropertySubType(ip); + string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType); + int nSubSpellID = StringToInt(sSpellIDStr); + + if (nSubSpellID == nSpellID) + { + // Vanilla uses CostTableValue for *number of uses*, not CL, + // so we’ll assume default caster level = spell level * 2 - 1 + int nSpellLevel = StringToInt(Get2DAString("spells", "Innate", nSubSpellID)); + nFoundCL = nSpellLevel * 2 - 1; // default NWN caster level rule + } + } + + ip = GetNextItemProperty(oItem); + } + + return nFoundCL; // -1 if not found +} + + +/** + * @brief Checks if a given spell ID is present on the specified class's spell list for the caster. + * + * This function determines the spell level of the spell for the given class using PRCGetSpellLevelForClass. + * If the spell level is -1, the spell is not on the class's spell list. + * Otherwise, the spell is considered to be on the class spell list. + * + * @param oCaster The creature object casting or querying the spell. + * @param nSpellID The spell ID to check. + * @param nClass The class index to check the spell list against. + * + * @return TRUE if the spell is on the class's spell list; FALSE otherwise. + */ +int GetIsClassSpell(object oCaster, int nSpellID, int nClass) +{ + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nSpellID is: "+IntToString(nSpellID)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nClass is: "+IntToString(nClass)+"."); + + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClass); + if (nSpellLevel == -1) + { + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: SpellLevel is "+IntToString(nSpellLevel)+"."); + if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: Spell "+IntToString(nSpellID)+" is not in spelllist of "+IntToString(nClass)+"."); + return FALSE; + } + return TRUE; +} + +/** + * @brief Checks if the caster has the specified spell on any of their class spell lists. + * + * This function iterates through all classes the caster has (up to position 8), + * and returns TRUE if the spell is found on any class's spell list. + * + * @param oCaster The creature object to check. + * @param nSpellID The spell ID to search for. + * + * @return TRUE if the spell is present on at least one of the caster's class spell lists; + * FALSE otherwise. + */ +int GetHasSpellOnClassList(object oCaster, int nSpellID) +{ + int i; + for (i = 0; i <= 8; i++) + { + int nClass = GetClassByPosition(i, oCaster); + if (nClass == CLASS_TYPE_INVALID) continue; + + if (GetIsClassSpell(oCaster, nSpellID, nClass)) + { + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell found."); + return TRUE; + } + } + if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell not found."); + return FALSE; +} + +/** + * @brief Applies a poison nausea effect to the user when infusion use fails. + * + * This function performs an immediate Fortitude saving throw against poison DC based on infusion caster level. + * If the user fails and is not immune to poison, an infusion nausea effect is applied, replacing any existing one. + * A second saving throw is scheduled after 1 minute to attempt to remove the effect. + * + * @param oUser The creature who used the infusion and may be poisoned. + * @param nInfusionCL The caster level of the infusion used, affecting the DC of the saving throw. + */ +void ApplyInfusionPoison(object oUser, int nInfusionCL) +{ + int nDC = 10 + (nInfusionCL / 2); + int bImmune = GetIsImmune(oUser, IMMUNITY_TYPE_POISON); + + // First save immediately + if (!bImmune && !PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + // Remove existing infusion poison nausea effect before applying new + effect eOld = GetFirstEffect(oUser); + while (GetIsEffectValid(eOld)) + { + if (GetEffectTag(eOld) == "INFUSION_POISON_TAG") + { + RemoveEffect(oUser, eOld); + break; // Assuming only one effect with this tag + } + eOld = GetNextEffect(oUser); + } + + effect eNausea = EffectNausea(oUser, 60.0f); + + TagEffect(eNausea, "INFUSION_POISON_TAG"); + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eNausea, oUser, RoundsToSeconds(10)); + } + + // Second save 1 minute later + if (!bImmune) + { + DelayCommand(60.0, InfusionSecondSave(oUser, nDC)); + } +} + +void InfusionSecondSave(object oUser, int nDC) +{ + if (!PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON)) + { + FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oUser, 60.0f), oUser, RoundsToSeconds(10)); + } +} + +//:: void main (){} \ No newline at end of file diff --git a/src/include/inc_lookups.nss b/src/include/inc_lookups.nss index e5a5124..fa68b5c 100644 --- a/src/include/inc_lookups.nss +++ b/src/include/inc_lookups.nss @@ -242,25 +242,27 @@ void SetupLookupStage(object oMod, int n) case 11: SetLkupStage(n, oMod, CLASS_TYPE_DRAGON_SHAMAN, "cls_inv_drgshm"); break; case 12: SetLkupStage(n, oMod, CLASS_TYPE_WARLOCK, "cls_inv_warlok"); break; case 13: SetLkupStage(n, oMod, CLASS_TYPE_ARCHIVIST, "cls_spell_archv"); break; - case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; - case 15: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; - case 16: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; - case 17: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; - case 18: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; - case 19: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; - case 20: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; - case 21: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; - case 22: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; - case 23: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; - case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; - case 25: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; - case 26: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; - case 27: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; - case 28: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; - case 29: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; - case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; - case 31: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; - case 32: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + case 14: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break; + case 15: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break; + case 16: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break; + case 17: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break; + case 18: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break; + case 19: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break; + case 20: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break; + case 21: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break; + case 22: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break; + case 23: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break; + case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break; + case 25: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break; + case 26: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break; + case 27: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break; + case 28: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break; + case 29: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break; + case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break; + case 31: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break; + + //:: These were all moved to the Bioware spellbooks -Jaysyn + //case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break; //case 46: SetLkupStage(n, oMod, CLASS_TYPE_CULTIST_SHATTERED_PEAK, "cls_spell_cultst"); break; //case 40: SetLkupStage(n, oMod, CLASS_TYPE_NENTYAR_HUNTER, "cls_spell_hunter"); break; //case 28: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWLORD, "cls_spell_tfshad"); break; @@ -528,7 +530,7 @@ int SpellToSpellbookID(int nSpell) int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell)); if(nOutSpellID == 0) nOutSpellID = -1; - //if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID)); + if(DEBUG) DoDebug("inc_lookup >> SpellToSpellbookID: (nSpell: " + IntToString(nSpell) + ") = nOutSpellID: " + IntToString(nOutSpellID)); return nOutSpellID; } diff --git a/src/include/inc_newspellbook.nss b/src/include/inc_newspellbook.nss index 909b93d..542e2d5 100644 --- a/src/include/inc_newspellbook.nss +++ b/src/include/inc_newspellbook.nss @@ -8,7 +8,7 @@ Make cls_spcr_*.2da Make blank cls_spell_*.2da Add cls_spgn_*.2da to classes.2da Add class entry in prc_classes.2da -Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level +Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level (not needed for NWN:EE) Add class to PRCGetSpellSaveDC() in prc_add_spell_dc Add class to GetSpellbookTypeForClass() below Add class to GetAbilityScoreForClass() below @@ -119,6 +119,7 @@ int GetSpellbookTypeForClass(int nClass) switch(nClass) { case CLASS_TYPE_ARCHIVIST: + case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BLACKGUARD: case CLASS_TYPE_BLIGHTER: case CLASS_TYPE_CLERIC: @@ -141,7 +142,6 @@ int GetSpellbookTypeForClass(int nClass) case CLASS_TYPE_VIGILANT: case CLASS_TYPE_WIZARD: return SPELLBOOK_TYPE_PREPARED; - case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_BEGUILER: case CLASS_TYPE_CELEBRANT_SHARESS: @@ -559,7 +559,7 @@ int bKnowsAllClassSpells(int nClass) { //case CLASS_TYPE_WIZARD: case CLASS_TYPE_ARCHIVIST: - case CLASS_TYPE_ASSASSIN: + //case CLASS_TYPE_ASSASSIN: case CLASS_TYPE_BARD: case CLASS_TYPE_CELEBRANT_SHARESS: case CLASS_TYPE_CULTIST_SHATTERED_PEAK: @@ -580,7 +580,79 @@ int bKnowsAllClassSpells(int nClass) return TRUE; } + int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) +{ + // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either + if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass)) + { + if(DEBUG) DoDebug("GetSpellKnownMaxCount: No slots available for " + IntToString(nClass) + " level " + IntToString(nLevel) + " circle " + IntToString(nSpellLevel)); + return 0; + } + + int nKnown; + string sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); + + if(DEBUG) + { + DoDebug("GetSpellKnownMaxCount Details:"); + DoDebug("- Class: " + IntToString(nClass)); + DoDebug("- Passed Level: " + IntToString(nLevel)); + DoDebug("- Base Class Level: " + IntToString(GetLevelByClass(nClass, oPC))); + DoDebug("- Effective Level: " + IntToString(GetSpellslotLevel(nClass, oPC))); + DoDebug("- Spell Level: " + IntToString(nSpellLevel)); + DoDebug("- SpellKnownTable: " + sFile); + DoDebug("- MaxKnown from 2DA: " + sKnown); + } + + if(sKnown == "") + { + nKnown = -1; + if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers"); + } + else + nKnown = StringToInt(sKnown); + + if(nKnown == -1) + return 0; + + // COMPLETELY REWROTE THIS SECTION + // Bard and Sorcerer logic for prestige class advancement + if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD) + { + int baseClassLevel = GetLevelByClass(nClass, oPC); + int effectiveLevel = GetSpellslotLevel(nClass, oPC); + + // Debug the values we're checking + if(DEBUG) + { + DoDebug("Spont caster check - Base level: " + IntToString(baseClassLevel) + + ", Effective level: " + IntToString(effectiveLevel)); + } + + // If they have prestige class advancement OR special feats, they should get spells + if(effectiveLevel > baseClassLevel || + GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || + GetHasFeat(FEAT_DRACONIC_BREATH, oPC)) + { + // Allow them to get spells - do nothing here, return nKnown at the end + if(DEBUG) DoDebug("Spontaneous caster eligible for new spells"); + } + else + { + // No advancement, no special feats - no new spells + if(DEBUG) DoDebug("Spontaneous caster NOT eligible for new spells"); + return 0; + } + } + + if(DEBUG) DoDebug("Final spell known count: " + IntToString(nKnown)); + return nKnown; +} + + +/* int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) { // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either // @todo Check rules. There might be cases where this doesn't hold @@ -588,22 +660,9 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) return 0; int nKnown; string sFile; - // Bioware casters use their classes.2da-specified tables - /*if( nClass == CLASS_TYPE_WIZARD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_CLERIC - || nClass == CLASS_TYPE_DRUID - || nClass == CLASS_TYPE_PALADIN - || nClass == CLASS_TYPE_RANGER) - {*/ - sFile = Get2DACache("classes", "SpellKnownTable", nClass); - /*} - else - { - sFile = Get2DACache("classes", "FeatsTable", nClass); - sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231 - }*/ + + sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown); @@ -626,6 +685,7 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) } return nKnown; } + */ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) { @@ -693,6 +753,44 @@ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) } int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) +{ + // Get the lookup token created by MakeSpellbookLevelLoop() + string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); + object oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid"); + + // Add code to create the missing lookup object + if(DEBUG) DoDebug("Attempting to create missing spell lookup token"); + ExecuteScript("prc_create_spellb", oPC); + + // Try again after creating it + oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("Still couldn't create spell lookup token"); + return 0; + } + else + { + if(DEBUG) DoDebug("Successfully created spell lookup token"); + } + } + + // Read the total number of spells on the given level and determine how many are already known + int nTotal = array_get_size(oCache, "Lkup"); + int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass); + int nUnknown = nTotal - nKnown; + + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); + if(DEBUG) DoDebug(" Total spells in lookup: " + IntToString(nTotal) + ", Known spells: " + IntToString(nKnown)); + + return nUnknown; +} + + +/* int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) { // Get the lookup token created by MakeSpellbookLevelLoop() string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); @@ -709,7 +807,7 @@ int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); return nUnknown; -} +} */ void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "") { @@ -850,7 +948,7 @@ void SetupSpells(object oPC, int nClass) int nAbility = GetAbilityScoreForClass(nClass, oPC); int nSpellbookType = GetSpellbookTypeForClass(nClass); - if(DEBUG) DoDebug("SetupSpells\n" + if(DEBUG) DoDebug("SetupSpells()\n" + "nClass = " + IntToString(nClass) + "\n" + "nSpellslotLevel = " + IntToString(nLevel) + "\n" + "nAbility = " + IntToString(nAbility) + "\n" @@ -1178,7 +1276,7 @@ void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE) else if(GetLocalInt(OBJECT_SELF, "PRC_metamagic_state") == 1) SetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust", 0); } - + if (DEBUG) DoDebug("CastSpontaneousSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(OBJECT_SELF, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1330,6 +1428,8 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI string sFile = GetFileForClass(nClass); int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID)); + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellbookType is: "+IntToString(nSpellbookType)+"."); // Make sure the caster has uses of this spell remaining // 2009-9-20: Add metamagic feat abilities. -N-S @@ -1371,13 +1471,14 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI else if(nSpellLevel > 9)//now test the spell level { nMetamagic = METAMAGIC_NONE; - ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic")); + ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is too high! Casting spell without metamagic")); nSpellLevel = nSpellSlotLevel; } else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1) SetLocalInt(oPC, "MetamagicFeatAdjust", 0); } - + + if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+"."); CheckSpontSlots(nClass, nSpellID, nSpellLevel); if(GetLocalInt(oPC, "NSB_Cast")) ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE)); @@ -1460,7 +1561,7 @@ void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction = { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckPrepSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellbookID: " + IntToString(nSpellbookID) + "] = " + IntToString(nCount)); if(nCount < 1) { string sSpellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID))); @@ -1486,7 +1587,7 @@ void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsActio { DeleteLocalInt(OBJECT_SELF, "NSB_Cast"); int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellSlotLevel); - if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("NewSpellbookSpell >> CheckSpontSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellSlotLevel: " + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount)); if(nCount < 1) { // "You have no castings of spells of level " + IntToString(nSpellLevel) + " remaining" diff --git a/src/include/inc_switch_setup.nss b/src/include/inc_switch_setup.nss index afffaae..d21b16c 100644 --- a/src/include/inc_switch_setup.nss +++ b/src/include/inc_switch_setup.nss @@ -720,7 +720,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_polymorph", 155); SetPRCSwitch("PRC_FILE_END_portraits", 1300); SetPRCSwitch("PRC_FILE_END_prc_craft_alchem", 37); - SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 204); + SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 253); SetPRCSwitch("PRC_FILE_END_prc_craft_poison", 62); SetPRCSwitch("PRC_FILE_END_prc_domains", 59); SetPRCSwitch("PRC_FILE_END_prc_familiar", 10); @@ -767,7 +767,7 @@ void SetDefaultFileEnds() SetPRCSwitch("PRC_FILE_END_soundset", 453); SetPRCSwitch("PRC_FILE_END_soundsettype", 4); SetPRCSwitch("PRC_FILE_END_soundtypes", 1); - SetPRCSwitch("PRC_FILE_END_spells", 19348); + SetPRCSwitch("PRC_FILE_END_spells", 19400); //SetPRCSwitch("PRC_FILE_END_spellschools", 9); SetPRCSwitch("PRC_FILE_END_statescripts", 35); SetPRCSwitch("PRC_FILE_END_stringtokens", 92); @@ -876,6 +876,8 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_HARM); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_NEUTRALIZE_POISON); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_REMOVE_DISEASE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIO_UNLEARN); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_UNLEARN_SPELL_MAXNR); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_BIOWARE_DURATION); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_LOCAL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_NO_HOSTILE); @@ -1067,14 +1069,16 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_SCRIBESCROLL_COSTMODIFIER); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_MAXLEVEL); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_SCRIBESCROLL_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_MAXLEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_COSTMODIFIER); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CREATEINFUSION_COSTMODIFIER); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_CASTER_LEVEL); //spells diff --git a/src/include/moi_inc_moifunc.nss b/src/include/moi_inc_moifunc.nss index d48a441..a2b0a3b 100644 --- a/src/include/moi_inc_moifunc.nss +++ b/src/include/moi_inc_moifunc.nss @@ -1182,7 +1182,7 @@ int GetMaxEssentiaCapacityFeat(object oMeldshaper) // Don't allow more than they have if (nMax > GetTotalUsableEssentia(oMeldshaper)) nMax = GetTotalUsableEssentia(oMeldshaper); - //if (DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); + if(DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax)); return nMax; } diff --git a/src/include/nw_inc_gff.nss b/src/include/nw_inc_gff.nss new file mode 100644 index 0000000..533cf21 --- /dev/null +++ b/src/include/nw_inc_gff.nss @@ -0,0 +1,623 @@ +// This is a helper library for advanced use: It allows constructing arbitrary gff data. +// You can then spawn your object via JsonToObject(). +// +// The data format is the same as https://github.com/niv/neverwinter.nim@1.4.3+. +// +// Example: +// +// json j = GffCreateObject(OBJECT_TYPE_ITEM); +// j = GffAddInt(j, "BaseItem", BASE_ITEM_BELT); +// j = GffAddInt(j, "ModelPart1", 12); +// j = GffAddLocString(j, "LocalizedName", "hi!"); +// object belt = JsonToObject(j, GetLocation(OBJECT_SELF)); + + +const string GFF_FIELD_TYPE_STRUCT = "struct"; +const string GFF_FIELD_TYPE_LIST = "list"; +const string GFF_FIELD_TYPE_BYTE = "byte"; +const string GFF_FIELD_TYPE_CHAR = "char"; +const string GFF_FIELD_TYPE_WORD = "word"; +const string GFF_FIELD_TYPE_SHORT = "short"; +const string GFF_FIELD_TYPE_DWORD = "dword"; +const string GFF_FIELD_TYPE_INT = "int"; +const string GFF_FIELD_TYPE_DWORD64 = "dword64"; +const string GFF_FIELD_TYPE_INT64 = "int64"; +const string GFF_FIELD_TYPE_FLOAT = "float"; +const string GFF_FIELD_TYPE_DOUBLE = "double"; +const string GFF_FIELD_TYPE_RESREF = "resref"; +const string GFF_FIELD_TYPE_STRING = "cexostring"; +const string GFF_FIELD_TYPE_LOC_STRING = "cexolocstring"; + + +// Create a empty object of the given type. You need to manually fill in all +// GFF data with GffAddXXX. This will require understanding of the GFF file format +// and what data fields each object type requires. +json GffCreateObject(int nObjectType); +// Create a combined area format(CAF) object. You need to manually create the ARE and GIT objects with their required data fields. +json GffCreateArea(json jARE, json jGIT); + +// Returns the OBJECT_TYPE_* of jGff. +// Note: Will return 0 for invalid object types, including areas. +int GffGetObjectType(json jGff); +// Returns TRUE if jGff is a combined area format(CAF) object. +int GffGetIsArea(json jGff); + +// Returns TRUE if a field named sLabel of sType exists in jGff. +// * sLabel: Can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// * sType: An optional GFF_FIELD_TYPE_*, leave empty to check if sLabel exists regardless of type. +int GffGetFieldExists(json jGff, string sLabel, string sType = ""); + + +// Add a new field, will overwrite any existing fields with the same label even if the type is different. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to add the tag of an area to an empty combined area format(CAF) object you can do the following: +// json jArea = GffCreateArea(JsonObject(), JsonObject()); +// jArea = GffAddString(jArea, "ARE/value/Tag", "AREA_TAG"); + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1); +json GffAddList(json jGff, string sLabel, json jList); +json GffAddByte(json jGff, string sLabel, int v); +json GffAddChar(json jGff, string sLabel, int v); +json GffAddWord(json jGff, string sLabel, int v); +json GffAddShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword(json jGff, string sLabel, int v); +json GffAddInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffAddInt64(json jGff, string sLabel, int v); +json GffAddFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffAddDouble(json jGff, string sLabel, float v); +json GffAddResRef(json jGff, string sLabel, string v); +json GffAddString(json jGff, string sLabel, string v); +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Replace a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to replace the name of an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffReplaceLocString(jArea, "ARE/value/Name", "New Area Name"); + +json GffReplaceStruct(json jGff, string sLabel, json jStruct); +json GffReplaceList(json jGff, string sLabel, json jList); +json GffReplaceByte(json jGff, string sLabel, int v); +json GffReplaceChar(json jGff, string sLabel, int v); +json GffReplaceWord(json jGff, string sLabel, int v); +json GffReplaceShort(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword(json jGff, string sLabel, int v); +json GffReplaceInt(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceDword64(json jGff, string sLabel, int v); +// Note: Only data of type int32 will fit, because that's all that NWScript supports. +json GffReplaceInt64(json jGff, string sLabel, int v); +json GffReplaceFloat(json jGff, string sLabel, float v); +// Note: Only data of type float will fit, because that's all that NWScript supports. +json GffReplaceDouble(json jGff, string sLabel, float v); +json GffReplaceResRef(json jGff, string sLabel, string v); +json GffReplaceString(json jGff, string sLabel, string v); +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1); + + +// Remove a field, the type must match and the field must exist. +// Returns a json null value on error with GetJsonError() filled in. +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to remove all placeables from an area in a combined area format(CAF) object you can do the following: +// json jArea = ObjectToStruct(GetFirstArea()); +// jArea = GffRemoveList(jArea, "GIT/value/Placeable List"); + +json GffRemoveStruct(json jGff, string sLabel); +json GffRemoveList(json jGff, string sLabel); +json GffRemoveByte(json jGff, string sLabel); +json GffRemoveChar(json jGff, string sLabel); +json GffRemoveWord(json jGff, string sLabel); +json GffRemoveShort(json jGff, string sLabel); +json GffRemoveDword(json jGff, string sLabel); +json GffRemoveInt(json jGff, string sLabel); +json GffRemoveDword64(json jGff, string sLabel); +json GffRemoveInt64(json jGff, string sLabel); +json GffRemoveFloat(json jGff, string sLabel); +json GffRemoveDouble(json jGff, string sLabel); +json GffRemoveResRef(json jGff, string sLabel); +json GffRemoveString(json jGff, string sLabel); +json GffRemoveLocString(json jGff, string sLabel); + + +// Get a field's value as json object. +// Returns a json null value on error with GetJsonError() filled in. +// +// Note: Json types do not implicitly convert between types, this means you cannot convert a JsonInt to a string with JsonGetString(), etc. +// You may need to check the type with JsonGetType() and then do the appropriate cast yourself. +// For GffGet*() functions the json type returned is noted in the function description. +// +// Example: +// INCORRECT: string s = JsonGetString(GffGetInt()); +// CORRECT: string s = IntToString(JsonGetInt(GffGetInt())); +// +// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details. +// For example, to get the resref of an area in a combined area format(CAF) object you can do the following: +// json jResRef = GffGetResRef(ObjectToStruct(GetFirstArea()), "ARE/value/ResRef"); +// if (jResRef != JsonNull()) +// { +// string sResRef = JsonGetString(jResRef); +// } +// else +// WriteTimestampedLogEntry("Failed to get area ResRef: " + JsonGetError(jResRef)); + +// Returns the struct as JsonObject() on success. +json GffGetStruct(json jGff, string sLabel); +// Returns a JsonArray() with all the list elements on success. +json GffGetList(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetByte(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetChar(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetWord(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetShort(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetDword64(json jGff, string sLabel); +// Returns a JsonInt() on success. +json GffGetInt64(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetFloat(json jGff, string sLabel); +// Returns a JsonFloat() on success. +json GffGetDouble(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetResRef(json jGff, string sLabel); +// Returns a JsonString() on success. +json GffGetString(json jGff, string sLabel); +// Returns a JsonObject() on success. +// Key "0" will have a JsonString() with the string, if set. +// Key "id" will have a JsonInt() with the strref, if set. +json GffGetLocString(json jGff, string sLabel); + + +// *** Internal Helper Functions +json AddPatchOperation(json jPatchArray, string sOp, string sPath, json jValue) +{ + json jOperation = JsonObject(); + jOperation = JsonObjectSet(jOperation, "op", JsonString(sOp)); + jOperation = JsonObjectSet(jOperation, "path", JsonString(sPath)); + jOperation = JsonObjectSet(jOperation, "value", jValue); + return JsonArrayInsert(jPatchArray, jOperation); +} + +json GffAddField(json jGff, string sLabel, string sType, json jValue, int nType = -1) +{ + json jField = JsonObject(); + jField = JsonObjectSet(jField, "type", JsonString(sType)); + jField = JsonObjectSet(jField, "value", jValue); + if (sType == GFF_FIELD_TYPE_STRUCT && nType != -1) + jField = JsonObjectSet(jField, "__struct_id", JsonInt(nType)); + + return JsonPatch(jGff, AddPatchOperation(JsonArray(), "add", "/" + sLabel, jField)); +} + +json GffReplaceField(json jGff, string sLabel, string sType, json jValue) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "replace", "/" + sLabel + "/value", jValue); + return JsonPatch(jGff, jPatch); +} + +json GffRemoveField(json jGff, string sLabel, string sType) +{ + json jPatch = JsonArray(); + jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType)); + jPatch = AddPatchOperation(jPatch, "remove", "/" + sLabel, JsonNull()); + return JsonPatch(jGff, jPatch); +} + +json GffGetFieldType(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/type"); +} + +json GffGetFieldValue(json jGff, string sLabel) +{ + return JsonPointer(jGff, "/" + sLabel + "/value"); +} + +json GffGetField(json jGff, string sLabel, string sType) +{ + json jType = GffGetFieldType(jGff, sLabel); + if (jType == JsonNull()) + return jType; + else if (jType != JsonString(sType)) + return JsonNull("field type does not match"); + else + return GffGetFieldValue(jGff, sLabel); +} + +json GffLocString(string v, int nStrRef = -1) +{ + json jLocString = JsonObject(); + if (v != "") + jLocString = JsonObjectSet(jLocString, "0", JsonString(v)); // english/any + if (nStrRef != -1) + jLocString = JsonObjectSet(jLocString, "id", JsonInt(nStrRef)); + + return jLocString; +} +//*** + +json GffCreateObject(int nObjectType) +{ + string ot; + if (nObjectType == OBJECT_TYPE_CREATURE) ot = "UTC "; + else if (nObjectType == OBJECT_TYPE_ITEM) ot = "UTI "; + else if (nObjectType == OBJECT_TYPE_TRIGGER) ot = "UTT "; + else if (nObjectType == OBJECT_TYPE_DOOR) ot = "UTD "; + else if (nObjectType == OBJECT_TYPE_WAYPOINT) ot = "UTW "; + else if (nObjectType == OBJECT_TYPE_PLACEABLE) ot = "UTP "; + else if (nObjectType == OBJECT_TYPE_STORE) ot = "UTM "; + else if (nObjectType == OBJECT_TYPE_ENCOUNTER) ot = "UTE "; + + if (ot == "") return JsonNull("invalid object type"); + + json ret = JsonObject(); + ret = JsonObjectSet(ret, "__data_type", JsonString(ot)); + return ret; +} + +json GffCreateArea(json jARE, json jGIT) +{ + json jCAF = JsonObject(); + jCAF = JsonObjectSet(jCAF, "__data_type", JsonString("CAF ")); + jCAF = GffAddStruct(jCAF, "ARE", jARE, 0); + jCAF = GffAddStruct(jCAF, "GIT", jGIT, 1); + return jCAF; +} + + +int GffGetObjectType(json jGff) +{ + json jDataType = JsonObjectGet(jGff, "__data_type"); + if (jDataType == JsonNull()) + return 0; + else + { + string sObjectType = JsonGetString(jDataType); + + if (sObjectType == "UTC ") return OBJECT_TYPE_CREATURE; + else if (sObjectType == "UTI ") return OBJECT_TYPE_ITEM; + else if (sObjectType == "UTT ") return OBJECT_TYPE_TRIGGER; + else if (sObjectType == "UTD ") return OBJECT_TYPE_DOOR; + else if (sObjectType == "UTW ") return OBJECT_TYPE_WAYPOINT; + else if (sObjectType == "UTP ") return OBJECT_TYPE_PLACEABLE; + else if (sObjectType == "UTM ") return OBJECT_TYPE_STORE; + else if (sObjectType == "UTE ") return OBJECT_TYPE_ENCOUNTER; + } + + return 0; +} + +int GffGetIsArea(json jGff) +{ + return JsonObjectGet(jGff, "__data_type") == JsonString("CAF "); +} + +int GffGetFieldExists(json jGff, string sLabel, string sType = "") +{ + json jFieldType = GffGetFieldType(jGff, sLabel); + return sType == "" ? jFieldType != JsonNull() : jFieldType == JsonString(sType); +} + + +json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct, nType); +} + +json GffAddList(json jGff, string sLabel, json jList) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffAddByte(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffAddChar(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffAddWord(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffAddShort(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffAddDword(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffAddInt(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffAddDword64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffAddInt64(json jGff, string sLabel, int v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffAddFloat(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffAddDouble(json jGff, string sLabel, float v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffAddResRef(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffAddString(json jGff, string sLabel, string v) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffReplaceStruct(json jGff, string sLabel, json jStruct) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct); +} + +json GffReplaceList(json jGff, string sLabel, json jList) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList); +} + +json GffReplaceByte(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v)); +} + +json GffReplaceChar(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v)); +} + +json GffReplaceWord(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v)); +} + +json GffReplaceShort(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v)); +} + +json GffReplaceDword(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v)); +} + +json GffReplaceInt(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v)); +} + +json GffReplaceDword64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v)); +} + +json GffReplaceInt64(json jGff, string sLabel, int v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v)); +} + +json GffReplaceFloat(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v)); +} + +json GffReplaceDouble(json jGff, string sLabel, float v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v)); +} + +json GffReplaceResRef(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v)); +} + +json GffReplaceString(json jGff, string sLabel, string v) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v)); +} + +json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1) +{ + return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef)); +} + + +json GffRemoveStruct(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffRemoveList(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffRemoveByte(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffRemoveChar(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffRemoveWord(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffRemoveShort(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffRemoveDword(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffRemoveInt(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffRemoveDword64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffRemoveInt64(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffRemoveFloat(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffRemoveDouble(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffRemoveResRef(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffRemoveString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffRemoveLocString(json jGff, string sLabel) +{ + return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} + + +json GffGetStruct(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT); +} + +json GffGetList(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LIST); +} + +json GffGetByte(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_BYTE); +} + +json GffGetChar(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_CHAR); +} + +json GffGetWord(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_WORD); +} + +json GffGetShort(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_SHORT); +} + +json GffGetDword(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD); +} + +json GffGetInt(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT); +} + +json GffGetDword64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64); +} + +json GffGetInt64(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT64); +} + +json GffGetFloat(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT); +} + +json GffGetDouble(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE); +} + +json GffGetResRef(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_RESREF); +} + +json GffGetString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRING); +} + +json GffGetLocString(json jGff, string sLabel) +{ + return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING); +} diff --git a/src/include/nw_inc_nui.nss b/src/include/nw_inc_nui.nss index 96fc3da..a37f13f 100644 --- a/src/include/nw_inc_nui.nss +++ b/src/include/nw_inc_nui.nss @@ -40,6 +40,24 @@ const float NUI_STYLE_TERTIARY_HEIGHT = 30.0; const float NUI_STYLE_ROW_HEIGHT = 25.0; +// ----------------------- +// Bind params + +// These currently only affect presentation and serve as a +// optimisation to let the client do the heavy lifting on this. +// In particular, this enables you to bind an array of values and +// transform them all at once on the client, instead of having to +// have the server transform them before sending. + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_NUMBER_FLAG_HEX = 0x001; + +// NB: These must be OR-ed together into a bitmask. + +const int NUI_TEXT_FLAG_LOWERCASE = 0x001; +const int NUI_TEXT_FLAG_UPPERCASE = 0x002; + // ----------------------- // Window @@ -47,24 +65,41 @@ const float NUI_STYLE_ROW_HEIGHT = 25.0; // * Set the window title to JsonBool(FALSE), Collapse to JsonBool(FALSE) and bClosable to FALSE // to hide the title bar. // Note: You MUST provide a way to close the window some other way, or the user will be stuck with it. -json // Window -NuiWindow( - json jRoot, // Layout-ish (NuiRow, NuiCol, NuiGroup) - json jTitle, // Bind:String - json jGeometry, // Bind:Rect Set x and/or y to -1.0 to center the window on that axis - // Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis - // Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis - json jResizable, // Bind:Bool Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. - json jCollapsed, // Bind:Bool Set to a static value JsonBool(FALSE) to disable collapsing. - // Set to JsonNull() to let user collapse without binding. - // For better UX, leave collapsing on. - json jClosable, // Bind:Bool You must provide a way to close the window if you set this to FALSE. - // For better UX, handle the window "closed" event. - json jTransparent, // Bind:Bool Do not render background - json jBorder, // Bind:Bool Do not render border - json jAcceptsInput = // Bind:Bool Set JsonBool(FALSE) to disable all input. - JSON_TRUE // All hover, clicks and keypresses will fall through. -); +// * Set a minimum size constraint equal to the maximmum size constraint in the same dimension to prevent +// a window from being resized in that dimension. +// - jRoot: Layout-ish (NuiRow, NuiCol, NuiGroup) +// - jTitle: Bind:String +// - jGeometry: Bind:Rect +// Set x and/or y to -1.0 to center the window on that axis. +// Set x and/or y to -2.0 to position the window's top left at the mouse cursor's position of that axis. +// Set x and/or y to -3.0 to center the window on the mouse cursor's position of that axis. +// - jResizable: Bind:Bool +// Set to JsonBool(TRUE) or JsonNull() to let user resize without binding. +// - jCollapsed: Bind:Bool +// Set to a static value JsonBool(FALSE) to disable collapsing. +// Set to JsonNull() to let user collapse without binding. +// For better UX, leave collapsing on. +// - jCloseable: Bind:Bool +// You provide a way to close the window if you set this to FALSE. +// For better UX, handle the window "closed" event. +// - jTransparent: Bind:Bool +// Do not render background +// - jBorder: Bind:Bool +// Do not render border +// - jAcceptsInput: Bind:Bool +// Set JsonBool(FALSE) to disable all input. +// All hover, clicks and keypresses will fall through. +// - jSizeConstraint: Bind:Rect +// Constrains minimum and maximum size of window. +// Set x to minimum width, y to minimum height, w to maximum width, h to maximum height. +// Set any individual constraint to 0.0 to ignore that constraint. +// - jEdgeConstraint: Bind:Rect +// Prevents a window from being rendered within the specified margins. +// Set x to left margin, y to top margin, w to right margin, h to bottom margin. +// Set any individual constraint to 0.0 to ignore that constraint +// - jFont: Bind:String +// Override font used on window, including decorations. See NuiStyleFont() for details. +json NuiWindow(json jRoot, json jTitle, json jGeometry, json jResizable,json jCollapsed,json jClosable, json jTransparent, json jBorder, json jAcceptsInput = JSON_TRUE, json jSizeConstraint = JSON_NULL, json jEdgeConstraint = JSON_NULL, json jFont = JSON_STRING); // ----------------------- // Values @@ -74,144 +109,111 @@ NuiWindow( // NuiSetBind(.., "mybindlabel", JsonString("hi")); // To create static values, just use the json types directly: // JsonString("hi"); -json // Bind -NuiBind( - string sId -); +// +// You can parametrise this particular bind with the given flags. +// These flags only apply to that particular usage of this bind value. +// +// - sId: string +// - nNumberFlags: bitmask of NUI_NUMBER_FLAG_* +// - nNumberPrecision: Precision to print number with (int or float) +// - nTextFlags: bitmask of NUI_TEXT_FLAG_* +json NuiBind(string sId, int nNumberFlags = 0, int nNumberPrecision = 0, int nTextFlags = 0); // Tag the given element with a id. // Only tagged elements will send events to the server. -json // Element -NuiId( - json jElem, // Element - string sId // String -); +json NuiId(json jElem, string sId); // A shim/helper that can be used to render or bind a strref where otherwise // a string value would go. -json -NuiStrRef( - int nStrRef // STRREF -); +json NuiStrRef(int nStrRef); // ----------------------- // Layout // A column will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiCol( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiCol(json jList); // A row will auto-space all elements inside of it and advise the parent // about it's desired size. -json // Layout -NuiRow( - json jList // Layout[] or Element[] -); +// - jList: Layout[] or Element[] +json NuiRow(json jList); // A group, usually with a border and some padding, holding a single element. Can scroll. // Will not advise parent of size, so you need to let it fill a span (col/row) as if it was // a element. -json // Layout -NuiGroup( - json jChild, // Layout or Element - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_AUTO -); +// - jChild: Layout or Element +json NuiGroup(json jChild, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // Modifiers/Attributes: These are all static and cannot be bound, since the UI system // cannot easily reflow once the layout is set up. You need to swap the layout if you // want to change element geometry. -json // Element -NuiWidth( - json jElem, // Element - float fWidth // Float: Element width in pixels (strength=required). -); +// - jElem: Element +// - fWidth: Float: Element width in pixels (strength=required). +json NuiWidth(json jElem, float fWidth); -json // Element -NuiHeight( - json jElem, // Element - float fHeight // Float: Height in pixels (strength=required). -); +// - jElem: Element +// - fHeight: Float: Height in pixels (strength=required). +json NuiHeight(json jElem, float fHeight); -json // Element -NuiAspect( - json jElem, // Element - float fAspect // Float: Ratio of x/y. -); +// - jElem: Element +// - fAspect: Float: Ratio of x/y +json NuiAspect(json jElem, float fAspect); // Set a margin on the widget. The margin is the spacing outside of the widget. -json // Element -NuiMargin( - json jElem, // Element - float fMargin // Float -); +json NuiMargin(json jElem, float fMargin); // Set padding on the widget. The margin is the spacing inside of the widget. -json // Element -NuiPadding( - json jElem, // Element - float fPadding // Float -); +json NuiPadding(json jElem, float fPadding); // Disabled elements are non-interactive and greyed out. -json // Element -NuiEnabled( - json jElem, // Element - json jEnabler // Bind:Bool -); +// - jElem: Element +// - jEnabled: Bind:Bool +json NuiEnabled(json jElem, json jEnabler); // Invisible elements do not render at all, but still take up layout space. -json // Element -NuiVisible( - json jElem, // Element - json jVisible // Bind:Bool -); +// - jElem: Element +// - jVisible: Bind:Bool +json NuiVisible(json jElem, json jVisible); // Tooltips show on mouse hover. -json // Element -NuiTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiTooltip(json jElem, json jTooltip); // Tooltips for disabled elements show on mouse hover. -json // Element -NuiDisabledTooltip( - json jElem, // Element - json jTooltip // Bind:String -); +// - jElem: Element +// - jTooltip: Bind:String +json NuiDisabledTooltip(json jElem, json jTooltip); // Encouraged elements have a breathing animated glow inside of it. -json // Element -NuiEncouraged( - json jElem, // Element - json jEncouraged // Bind:Bool -); +// - jElem: Element +// - jEncouraged: Bind:Bool +json NuiEncouraged(json jElem, json jEncouraged); // ----------------------- // Props & Style -json // Vec2 -NuiVec(float x, float y); +json NuiVec(float x, float y); -json // Rect -NuiRect(float x, float y, float w, float h); +json NuiRect(float x, float y, float w, float h); -json // Color -NuiColor(int r, int g, int b, int a = 255); +json NuiColor(int r, int g, int b, int a = 255); -// Style the foreground color of the widget. This is dependent on the widget +// Style the foreground color of a widget or window title. This is dependent on the widget // in question and only supports solid/full colors right now (no texture skinning). // For example, labels would style their text color; progress bars would style the bar. -json // Element -NuiStyleForegroundColor( - json jElem, // Element - json jColor // Bind:Color -); +// - jElem: Element +// - jColor: Bind:Color +json NuiStyleForegroundColor(json jElem, json jColor); + +// Override the font used for this element. The font and it's properties needs to be listed in +// nui_skin.tml, as all fonts are pre-baked into a texture atlas at content load. +// - jElem: Element +// - jColor: Bind:String ([[fonts]].name in nui_skin.tml) +json NuiStyleFont(json jElem, json jFont); // ----------------------- // Widgets @@ -219,119 +221,87 @@ NuiStyleForegroundColor( // A special widget that just takes up layout space. // If you add multiple spacers to a span, they will try to size equally. // e.g.: [ ] will try to center the button. -json // Element -NuiSpacer(); +json NuiSpacer(); // Create a label field. Labels are single-line stylable non-editable text fields. -json // Element -NuiLabel( - json jValue, // Bind:String - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jValue: Bind:String +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiLabel(json jValue, json jHAlign, json jVAlign); // Create a non-editable text field. Note: This text field internally implies a NuiGroup wrapped // around it, which is providing the optional border and scrollbars. -json // Element -NuiText( - json jValue, // Bind:String - int bBorder = TRUE, // Bool - int nScroll = NUI_SCROLLBARS_AUTO // Int:NUI_SCROLLBARS_* -); +// - jValue: Bind:String +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_* +json NuiText(json jValue, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO); // A clickable button with text as the label. // Sends "click" events on click. -json // Element -NuiButton( - json jLabel // Bind:String -); +// - jLabel: Bind:String +json NuiButton(json jLabel); // A clickable button with an image as the label. // Sends "click" events on click. -json // Element -NuiButtonImage( - json jResRef // Bind:ResRef -); +// - jResRef: Bind:String +json NuiButtonImage(json jResRef); // A clickable button with text as the label. // Same as the normal button, but this one is a toggle. // Sends "click" events on click. -json // Element -NuiButtonSelect( - json jLabel, // Bind:String - json jValue // Bind:Bool -); +// - jLabel: Bind:String +// - jValue: Bind:Bool +json NuiButtonSelect(json jLabel, json jValue); // A checkbox with a label to the right of it. -json // Element -NuiCheck( - json jLabel, // Bind:String - json jBool // Bind:Bool -); +// - jLabel: Bind:String +// - jBool: Bind:Bool +json NuiCheck(json jLabel, json jBool); // A image, with no border or padding. -json // Element -NuiImage( - json jResRef, // Bind:ResRef - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign // Bind:Int:NUI_VALIGN_* -); +// - jResRef: Bind:String +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +json NuiImage(json jResRef, json jAspect, json jHAlign, json jVAlign); -// Optionally render only subregion of jImage. +// Optionally render only subregion of jImage. This property can be set on +// NuiImage and NuiButtonImage widgets. // jRegion is a NuiRect (x, y, w, h) to indicate the render region inside the image. -json // NuiImage -NuiImageRegion( - json jImage, // NuiImage - json jRegion // Bind:NuiRect -); +json NuiImageRegion(json jImage, json jRegion); // A combobox/dropdown. -json // Element -NuiCombo( - json jElements, // Bind:ComboEntry[] - json jSelected // Bind:Int (index into jElements) -); +// - jElements: Bind:ComboEntry[] +// - jSelected: Bind:Int (index into jElements) +json NuiCombo(json jElements, json jSelected); -json // ComboEntry -NuiComboEntry( - string sLabel, - int nValue -); +json NuiComboEntry(string sLabel, int nValue); // A floating-point slider. A good step size for normal-sized sliders is 0.01. -json // Element -NuiSliderFloat( - json jValue, // Bind:Float - json jMin, // Bind:Float - json jMax, // Bind:Float - json jStepSize // Bind:Float -); +// - jValue: Bind:Float +// - jMin: Bind:Float +// - jMax: Bind:Float +// - jStepSize: Bind:Float +json NuiSliderFloat(json jValue, json jMin, json jMax, json jStepSize); // A integer/discrete slider. -json // Element -NuiSlider( - json jValue, // Bind:Int - json jMin, // Bind:Int - json jMax, // Bind:Int - json jStepSize // Bind:Int -); +// - jValue: Bind:Int +// - jMin: Bind:Int +// - jMax: Bind:Int +// - jStepSize: Bind:Int +json NuiSlider(json jValue, json jMin, json jMax, json jStepSize); // A progress bar. Progress is always from 0.0 to 1.0. -json // Element -NuiProgress( - json jValue // Bind:Float (0.0->1.0) -); +// - jValue: Bind:Float (0.0->1.0 +json NuiProgress(json jValue); // A editable text field. -json // Element -NuiTextEdit( - json jPlaceholder, // Bind:String - json jValue, // Bind:String - int nMaxLength, // UInt >= 1, <= 65535 - int bMultiline, // Bool - int bWordWrap = TRUE // Bool -); +// - jPlaceholder: Bind:String +// - jValue: Bind:String +// - nMaxLength: UInt >= 1, <= 65535 +// - bMultiLine: Bool +// - bWordWrap: Bool +json NuiTextEdit(json jPlaceholder, json jValue, int nMaxLength, int bMultiline, int bWordWrap = TRUE); // Creates a list view of elements. // jTemplate needs to be an array of NuiListTemplateCell instances. @@ -339,67 +309,52 @@ NuiTextEdit( // e.g. when rendering a NuiLabel(), the bound label String should be an array of strings. // You can pass in one of the template jRowCount into jSize as a convenience. The array // size will be uses as the Int bind. -// jRowHeight defines the height of the rendered rows. -json // Element -NuiList( - json jTemplate, // NuiListTemplateCell[] (max: 16) - json jRowCount, // Bind:Int - float fRowHeight = NUI_STYLE_ROW_HEIGHT, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_Y // Note: Cannot be AUTO. -); +// fRowHeight defines the height of the rendered rows. +// - jTemplate: NuiListTemplateCell[] (max: 16) +// - jRowCount: Bind:Int +// - bBorder: Bool +// - nScroll: Int:NUI_SCROLLBARS_*, Note: Cannot be AUTO +json NuiList(json jTemplate, json jRowCount, float fRowHeight = NUI_STYLE_ROW_HEIGHT, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_Y); -json // NuiListTemplateCell -NuiListTemplateCell( - json jElem, // Element - float fWidth, // Float:0 = auto, >1 = pixel width - int bVariable // Bool:Cell can grow if space is available; otherwise static -); +// - jElem: Element +// - fWidth: Float:0 = auto, >1 = pixel width +// - bVariable: Bool:Cell can grow if space is available; otherwise static +json NuiListTemplateCell(json jElem, float fWidth, int bVariable); // A simple color picker, with no border or spacing. -json // Element -NuiColorPicker( - json jColor // Bind:Color -); +// - jColor: Bind:Color +json NuiColorPicker(json jColor); // A list of options (radio buttons). Only one can be selected // at a time. jValue is updated every time a different element is // selected. The special value -1 means "nothing". -json // Element -NuiOptions( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:UInt +json NuiOptions(int nDirection, json jElements, json jValue); -// A group of buttons. Only one can be selected at a time. jValue -// is updated every time a different button is selected. The special +// A group of buttons. Only one can be selected at a time. jValue +// is updated every time a different button is selected. The special // value -1 means "nothing". -json // Element -NuiToggles( - int nDirection, // NUI_DIRECTION_* - json jElements, // JsonArray of string labels - json jValue // Bind:Int -); +// - nDirection: NUI_DIRECTION_* +// - jElements: JsonArray of string labels +// - jValue: Bind:Int +json NuiToggles(int nDirection, json jElements, json jValue); const int NUI_CHART_TYPE_LINES = 0; const int NUI_CHART_TYPE_COLUMN = 1; -json // NuiChartSlot -NuiChartSlot( - int nType, // Int:NUI_CHART_TYPE_* - json jLegend, // Bind:String - json jColor, // Bind:NuiColor - json jData // Bind:Float[] -); +// - nType: Int:NUI_CHART_TYPE_* +// - jLegend: Bind:String +// - jColor: Bind:NuiColor +// - jData: Bind:Float[] +json NuiChartSlot(int nType, json jLegend, json jColor, json jData); // Renders a chart. // Currently, min and max values are determined automatically and // cannot be influenced. -json // Element -NuiChart( - json jSlots // NuiChartSlot[] -); +// - jSlots: NuiChartSlot[] +json NuiChart( json jSlots); // ----------------------- // Draw Lists @@ -417,6 +372,7 @@ const int NUI_DRAW_LIST_ITEM_TYPE_ARC = 3; const int NUI_DRAW_LIST_ITEM_TYPE_TEXT = 4; const int NUI_DRAW_LIST_ITEM_TYPE_IMAGE = 5; const int NUI_DRAW_LIST_ITEM_TYPE_LINE = 6; +const int NUI_DRAW_LIST_ITEM_TYPE_RECT = 7; // You can order draw list items to be painted either before, or after the // builtin render of the widget in question. This enables you to paint "behind" @@ -438,100 +394,100 @@ const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_RIGHT = 4; // Only render while MMB is held down. const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_MIDDLE = 5; -json // DrawListItem -NuiDrawListPolyLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jPoints, // Bind:Float[] Always provide points in pairs - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jPoints: Bind:Float[] Always provide points in pairs +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListPolyLine(json jEnabled, json jColor, json jFill, json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCurve( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - json jCtrl0, // Bind:Vec2 - json jCtrl1, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - jCtrl0: Bind:Vec2 +// - jCtrl1: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCurve(json jEnabled, json jColor, json jLineThickness, json jA, json jB, json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListCircle( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jRect, // Bind:Rect - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRect: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListCircle(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListArc( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jFill, // Bind:Bool - json jLineThickness, // Bind:Float - json jCenter, // Bind:Vec2 - json jRadius, // Bind:Float - json jAMin, // Bind:Float - json jAMax, // Bind:Float - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jCenter: Bind:Rect +// - jRadius: Bind:Float +// - jAMin: Bind:Float +// - jAMax: Bind:Float +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListArc(json jEnabled, json jColor, json jFill, json jLineThickness, json jCenter, json jRadius, json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItem -NuiDrawListText( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jRect, // Bind:Rect - json jText, // Bind:String - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jRect: Bind:Rect +// - jText: Bind:String +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +// - jFont: Bind:String +json NuiDrawListText(json jEnabled, json jColor, json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE, json jFont = JSON_STRING); -json // DrawListItem -NuiDrawListImage( - json jEnabled, // Bind:Bool - json jResRef, // Bind:ResRef - json jPos, // Bind:Rect - json jAspect, // Bind:Int:NUI_ASPECT_* - json jHAlign, // Bind:Int:NUI_HALIGN_* - json jVAlign, // Bind:Int:NUI_VALIGN_* - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jResRef: Bind:String +// - jPos: Bind:Rect +// - jAspect: Bind:Int:NUI_ASPECT_* +// - jHAlign: Bind:Int:NUI_HALIGN_* +// - jVAlign: Bind:Int:NUI_VALIGN_* +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListImage(json jEnabled, json jResRef, json jPos, json jAspect, json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // DrawListItemImage -NuiDrawListImageRegion( - json jDrawListImage, // DrawListItemImage - json jRegion // Bind:NuiRect -); +// - jDrawListImage: DrawListItemImage +// - jRegion: Bind:NuiRect +json NuiDrawListImageRegion(json jDrawListImage, json jRegion); -json // DrawListItem -NuiDrawListLine( - json jEnabled, // Bind:Bool - json jColor, // Bind:Color - json jLineThickness, // Bind:Float - json jA, // Bind:Vec2 - json jB, // Bind:Vec2 - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, // Int:NUI_DRAW_LIST_ITEM_ORDER_* - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS // Int:NUI_DRAW_LIST_ITEM_RENDER_* -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jLineThickness: Bind:Float +// - jA: Bind:Vec2 +// - jB: Bind:Vec2 +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListLine(json jEnabled, json jColor, json jLineThickness, json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); -json // Element -NuiDrawList( - json jElem, // Element - json jScissor, // Bind:Bool Constrain painted elements to widget bounds. - json jList // DrawListItem[] -); +// - jEnabled: Bind:Bool +// - jColor: Bind:Color +// - jFill: Bind:Bool +// - jLineThickness: Bind:Float +// - jRext: Bind:Rect +// - nOrder: Int:NUI_DRAW_LIST_ITEM_ORDER_* +// - nRender: Int:NUI_DRAW_LIST_ITEM_RENDER_* +// - nBindArrays: Values in binds are considered arrays-of-values +json NuiDrawListRect(json jEnabled, json jColor, json jFill, json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, int nBindArrays = FALSE); + +// - jElem: Element +// - jScissor: Bind:Bool, Constrain painted elements to widget bounds. +// - jList: DrawListItem[] +json NuiDrawList(json jElem, json jScissor, json jList); // ----------------------- // Implementation @@ -546,21 +502,27 @@ NuiWindow( json jClosable, json jTransparent, json jBorder, - json jAcceptsInput + json jAcceptsInput = JSON_TRUE, + json jWindowConstraint = JSON_NULL, + json jEdgeConstraint = JSON_NULL, + json jFont = JSON_STRING ) { json ret = JsonObject(); // Currently hardcoded and here to catch backwards-incompatible data in the future. - ret = JsonObjectSet(ret, "version", JsonInt(1)); - ret = JsonObjectSet(ret, "title", jTitle); - ret = JsonObjectSet(ret, "root", jRoot); - ret = JsonObjectSet(ret, "geometry", jGeometry); - ret = JsonObjectSet(ret, "resizable", jResizable); - ret = JsonObjectSet(ret, "collapsed", jCollapsed); - ret = JsonObjectSet(ret, "closable", jClosable); - ret = JsonObjectSet(ret, "transparent", jTransparent); - ret = JsonObjectSet(ret, "border", jBorder); - ret = JsonObjectSet(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "version", JsonInt(1)); + JsonObjectSetInplace(ret, "title", jTitle); + JsonObjectSetInplace(ret, "root", jRoot); + JsonObjectSetInplace(ret, "geometry", jGeometry); + JsonObjectSetInplace(ret, "resizable", jResizable); + JsonObjectSetInplace(ret, "collapsed", jCollapsed); + JsonObjectSetInplace(ret, "closable", jClosable); + JsonObjectSetInplace(ret, "transparent", jTransparent); + JsonObjectSetInplace(ret, "border", jBorder); + JsonObjectSetInplace(ret, "accepts_input", jAcceptsInput); + JsonObjectSetInplace(ret, "size_constraint", jWindowConstraint); + JsonObjectSetInplace(ret, "edge_constraint", jEdgeConstraint); + JsonObjectSetInplace(ret, "font", jFont); return ret; } @@ -572,18 +534,26 @@ NuiElement( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonString(sType)); - ret = JsonObjectSet(ret, "label", jLabel); - ret = JsonObjectSet(ret, "value", jValue); + JsonObjectSetInplace(ret, "type", JsonString(sType)); + JsonObjectSetInplace(ret, "label", jLabel); + JsonObjectSetInplace(ret, "value", jValue); return ret; } json NuiBind( - string sId + string sId, + int nNumberFlags = 0, + int nNumberPrecision = 0, + int nTextFlags = 0 ) { - return JsonObjectSet(JsonObject(), "bind", JsonString(sId)); + json ret = JsonObject(); + JsonObjectSetInplace(ret, "bind", JsonString(sId)); + JsonObjectSetInplace(ret, "number_flags", JsonInt(nNumberFlags)); + JsonObjectSetInplace(ret, "number_precision", JsonInt(nNumberPrecision)); + JsonObjectSetInplace(ret, "text_flags", JsonInt(nTextFlags)); + return ret; } json @@ -601,7 +571,7 @@ NuiStrRef( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "strref", JsonInt(nStrRef)); + JsonObjectSetInplace(ret, "strref", JsonInt(nStrRef)); return ret; } @@ -629,9 +599,9 @@ NuiGroup( ) { json ret = NuiElement("group", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "children", JsonArrayInsert(JsonArray(), jChild)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "children", JsonArrayInsert(JsonArray(), jChild)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -720,8 +690,8 @@ json NuiVec(float x, float y) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); return ret; } @@ -729,10 +699,10 @@ json NuiRect(float x, float y, float w, float h) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); - ret = JsonObjectSet(ret, "w", JsonFloat(w)); - ret = JsonObjectSet(ret, "h", JsonFloat(h)); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "w", JsonFloat(w)); + JsonObjectSetInplace(ret, "h", JsonFloat(h)); return ret; } @@ -740,10 +710,10 @@ json NuiColor(int r, int g, int b, int a = 255) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "r", JsonInt(r)); - ret = JsonObjectSet(ret, "g", JsonInt(g)); - ret = JsonObjectSet(ret, "b", JsonInt(b)); - ret = JsonObjectSet(ret, "a", JsonInt(a)); + JsonObjectSetInplace(ret, "r", JsonInt(r)); + JsonObjectSetInplace(ret, "g", JsonInt(g)); + JsonObjectSetInplace(ret, "b", JsonInt(b)); + JsonObjectSetInplace(ret, "a", JsonInt(a)); return ret; } @@ -756,6 +726,15 @@ NuiStyleForegroundColor( return JsonObjectSet(jElem, "foreground_color", jColor); } +json +NuiStyleFont( + json jElem, + json jFont +) +{ + return JsonObjectSet(jElem, "font", jFont); +} + json NuiSpacer() { @@ -770,8 +749,8 @@ NuiLabel( ) { json ret = NuiElement("label", JsonNull(), jValue); - ret = JsonObjectSet(ret, "text_halign", jHAlign); - ret = JsonObjectSet(ret, "text_valign", jVAlign); + JsonObjectSetInplace(ret, "text_halign", jHAlign); + JsonObjectSetInplace(ret, "text_valign", jVAlign); return ret; } @@ -783,8 +762,8 @@ NuiText( ) { json ret = NuiElement("text", JsonNull(), jValue); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -831,9 +810,9 @@ NuiImage( ) { json img = NuiElement("image", JsonNull(), jResRef); - img = JsonObjectSet(img, "image_aspect", jAspect); - img = JsonObjectSet(img, "image_halign", jHAlign); - img = JsonObjectSet(img, "image_valign", jVAlign); + JsonObjectSetInplace(img, "image_aspect", jAspect); + JsonObjectSetInplace(img, "image_halign", jHAlign); + JsonObjectSetInplace(img, "image_valign", jVAlign); return img; } @@ -873,9 +852,9 @@ NuiSliderFloat( ) { json ret = NuiElement("sliderf", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -888,9 +867,9 @@ NuiSlider( ) { json ret = NuiElement("slider", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); return ret; } @@ -912,9 +891,9 @@ NuiTextEdit( ) { json ret = NuiElement("textedit", jPlaceholder, jValue); - ret = JsonObjectSet(ret, "max", JsonInt(nMaxLength)); - ret = JsonObjectSet(ret, "multiline", JsonBool(bMultiline)); - ret = JsonObjectSet(ret, "wordwrap", JsonBool(bWordWrap)); + JsonObjectSetInplace(ret, "max", JsonInt(nMaxLength)); + JsonObjectSetInplace(ret, "multiline", JsonBool(bMultiline)); + JsonObjectSetInplace(ret, "wordwrap", JsonBool(bWordWrap)); return ret; } @@ -928,11 +907,11 @@ NuiList( ) { json ret = NuiElement("list", JsonNull(), JsonNull()); - ret = JsonObjectSet(ret, "row_template", jTemplate); - ret = JsonObjectSet(ret, "row_count", jRowCount); - ret = JsonObjectSet(ret, "row_height", JsonFloat(fRowHeight)); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); + JsonObjectSetInplace(ret, "row_template", jTemplate); + JsonObjectSetInplace(ret, "row_count", jRowCount); + JsonObjectSetInplace(ret, "row_height", JsonFloat(fRowHeight)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); return ret; } @@ -944,9 +923,9 @@ NuiListTemplateCell( ) { json ret = JsonArray(); - ret = JsonArrayInsert(ret, jElem); - ret = JsonArrayInsert(ret, JsonFloat(fWidth)); - ret = JsonArrayInsert(ret, JsonBool(bVariable)); + JsonArrayInsertInplace(ret, jElem); + JsonArrayInsertInplace(ret, JsonFloat(fWidth)); + JsonArrayInsertInplace(ret, JsonBool(bVariable)); return ret; } @@ -967,8 +946,8 @@ NuiOptions( ) { json ret = NuiElement("options", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -980,8 +959,8 @@ NuiToggles( ) { json ret = NuiElement("tabbar", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); return ret; } @@ -994,10 +973,10 @@ NuiChartSlot( ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "legend", jLegend); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "data", jData); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "legend", jLegend); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "data", jData); return ret; } @@ -1018,17 +997,19 @@ NuiDrawListItem( json jFill, json jLineThickness, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "enabled", jEnabled); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "fill", jFill); - ret = JsonObjectSet(ret, "line_thickness", jLineThickness); - ret = JsonObjectSet(ret, "order", JsonInt(nOrder)); - ret = JsonObjectSet(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "enabled", jEnabled); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "fill", jFill); + JsonObjectSetInplace(ret, "line_thickness", jLineThickness); + JsonObjectSetInplace(ret, "order", JsonInt(nOrder)); + JsonObjectSetInplace(ret, "render", JsonInt(nRender)); + JsonObjectSetInplace(ret, "arrayBinds", JsonBool(nBindArrays)); return ret; } @@ -1040,11 +1021,12 @@ NuiDrawListPolyLine( json jLineThickness, json jPoints, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "points", jPoints); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "points", jPoints); return ret; } @@ -1058,14 +1040,15 @@ NuiDrawListCurve( json jCtrl0, json jCtrl1, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); - ret = JsonObjectSet(ret, "ctrl0", jCtrl0); - ret = JsonObjectSet(ret, "ctrl1", jCtrl1); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CURVE, jEnabled, jColor, JsonBool(0), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + JsonObjectSetInplace(ret, "ctrl0", jCtrl0); + JsonObjectSetInplace(ret, "ctrl1", jCtrl1); return ret; } @@ -1077,11 +1060,12 @@ NuiDrawListCircle( json jLineThickness, json jRect, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1096,14 +1080,15 @@ NuiDrawListArc( json jAMin, json jAMax, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "c", jCenter); - ret = JsonObjectSet(ret, "radius", jRadius); - ret = JsonObjectSet(ret, "amin", jAMin); - ret = JsonObjectSet(ret, "amax", jAMax); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_ARC, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "c", jCenter); + JsonObjectSetInplace(ret, "radius", jRadius); + JsonObjectSetInplace(ret, "amin", jAMin); + JsonObjectSetInplace(ret, "amax", jAMax); return ret; } @@ -1114,12 +1099,15 @@ NuiDrawListText( json jRect, json jText, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE, + json jFont = JSON_STRING ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "text", jText); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_TEXT, jEnabled, jColor, JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "text", jText); + ret = NuiStyleFont(ret, jFont); return ret; } @@ -1132,15 +1120,16 @@ NuiDrawListImage( json jHAlign, json jVAlign, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender); - ret = JsonObjectSet(ret, "image", jResRef); - ret = JsonObjectSet(ret, "rect", jRect); - ret = JsonObjectSet(ret, "image_aspect", jAspect); - ret = JsonObjectSet(ret, "image_halign", jHAlign); - ret = JsonObjectSet(ret, "image_valign", jVAlign); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_IMAGE, jEnabled, JsonNull(), JsonNull(), JsonNull(), nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "image", jResRef); + JsonObjectSetInplace(ret, "rect", jRect); + JsonObjectSetInplace(ret, "image_aspect", jAspect); + JsonObjectSetInplace(ret, "image_halign", jHAlign); + JsonObjectSetInplace(ret, "image_valign", jVAlign); return ret; } @@ -1161,12 +1150,30 @@ NuiDrawListLine( json jA, json jB, int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE ) { - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "a", jA); - ret = JsonObjectSet(ret, "b", jB); + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_LINE, jEnabled, jColor, JsonNull(), jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "a", jA); + JsonObjectSetInplace(ret, "b", jB); + return ret; +} + +json +NuiDrawListRect( + json jEnabled, + json jColor, + json jFill, + json jLineThickness, + json jRect, + int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE +) +{ + json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_RECT, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); return ret; } @@ -1178,7 +1185,7 @@ NuiDrawList( ) { json ret = JsonObjectSet(jElem, "draw_list", jList); - ret = JsonObjectSet(ret, "draw_list_scissor", jScissor); + JsonObjectSetInplace(ret, "draw_list_scissor", jScissor); return ret; } @@ -1190,4 +1197,3 @@ NuiDrawList( // json ret = NuiElement("canvas", JsonNull(), jList); // return ret; // } - diff --git a/src/include/prc_add_spell_dc.nss b/src/include/prc_add_spell_dc.nss index 4cde6de..f2a0e2f 100644 --- a/src/include/prc_add_spell_dc.nss +++ b/src/include/prc_add_spell_dc.nss @@ -513,6 +513,8 @@ int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJE if(nClass == CLASS_TYPE_BARD) nDC += StringToInt(Get2DACache("Spells", "Bard", nSpellID)); + else if(nClass == CLASS_TYPE_ASSASSIN) + nDC += StringToInt(Get2DACache("Spells", "Assassin", nSpellID)); else if(nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR) nDC += StringToInt(Get2DACache("Spells", "Cleric", nSpellID)); else if(nClass == CLASS_TYPE_DRUID) diff --git a/src/include/prc_class_const.nss b/src/include/prc_class_const.nss index 286b574..04e96f1 100644 --- a/src/include/prc_class_const.nss +++ b/src/include/prc_class_const.nss @@ -143,7 +143,7 @@ const int CLASS_TYPE_MASTER_HARPER = 176; const int CLASS_TYPE_FRE_BERSERKER = 177; const int CLASS_TYPE_TEMPEST = 178; const int CLASS_TYPE_FOE_HUNTER = 179; -//:: Free = 180 +const int CLASS_TYPE_VERDANT_LORD = 180; const int CLASS_TYPE_ORC_WARLORD = 181; const int CLASS_TYPE_THRALL_OF_GRAZZT_A = 182; const int CLASS_TYPE_NECROCARNATE = 183; @@ -162,7 +162,7 @@ const int CLASS_TYPE_MASTER_OF_NINE = 195; const int CLASS_TYPE_ETERNAL_BLADE = 196; const int CLASS_TYPE_SHADOW_SUN_NINJA = 197; const int CLASS_TYPE_WITCHBORN_BINDER = 198; -const int CLASS_TYPE_BAELNORN = 199; +const int CLASS_TYPE_LION_OF_TALISID = 199; const int CLASS_TYPE_DISCIPLE_OF_MEPH = 200; const int CLASS_TYPE_SOUL_EATER = 201; const int CLASS_TYPE_HENSHIN_MYSTIC = 202; @@ -236,6 +236,7 @@ const int CLASS_TYPE_WITCH = -1; const int CLASS_TYPE_TEMPLAR = -1; const int CLASS_TYPE_MYSTIC = -1; const int CLASS_TYPE_NOBLE = -1; +const int CLASS_TYPE_BAELNORN = -2; //void main (){} \ No newline at end of file diff --git a/src/include/prc_effect_inc.nss b/src/include/prc_effect_inc.nss index 6186f71..4552481 100644 --- a/src/include/prc_effect_inc.nss +++ b/src/include/prc_effect_inc.nss @@ -75,6 +75,13 @@ void DeathlessFrenzyCheck(object oTarget); // * PRC Version of a Bioware function to disable include loops void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget); +/** + * Target is immune to gaze attacks + * + * @return the Dazzle effect + */ +effect EffectGazeImmune(); + /** * Dazzles the target: -1 Attack, Search, Spot, and VFX * @@ -583,7 +590,8 @@ effect PRCEffectHeal(int nHP, object oTarget) return EffectHeal(nHP); } -effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ +effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1) +{ effect eReturn; switch(iAbility) { @@ -639,7 +647,8 @@ effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){ return eReturn; } -effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ +effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1) +{ effect eReturn; switch(iAbility) { @@ -695,7 +704,8 @@ effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){ return eReturn; } -effect EffectDamageImmunityAll(){ +effect EffectDamageImmunityAll() +{ effect eReturn = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100)); eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100)); @@ -712,7 +722,8 @@ effect EffectDamageImmunityAll(){ return eReturn; } -effect EffectImmunityMiscAll(){ +effect EffectImmunityMiscAll() +{ effect eReturn = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_BLINDNESS)); eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEAFNESS)); @@ -732,6 +743,31 @@ effect EffectImmunityMiscAll(){ return eReturn; } +//:: Immunity to all gaze attacks +effect EffectGazeImmune() +{ + effect eBlank; + + effect eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CHARM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CONFUSION); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DAZE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DEATH); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_CHAOS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_EVIL); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_GOOD); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_LAW); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOMINATE); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOOM); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_FEAR); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PARALYSIS); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PETRIFY); + eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_STUNNED); + + eReturn = TagEffect(eReturn, "PRCGazeImmune"); + + return eReturn; +} + int GetIsShaken(object oTarget) { effect eEffect = GetFirstEffect(oTarget); @@ -747,4 +783,7 @@ int GetIsShaken(object oTarget) eEffect = GetNextEffect(oTarget); } return FALSE; -} \ No newline at end of file +} + +//:: Test void +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_feat_const.nss b/src/include/prc_feat_const.nss index c961dab..8035960 100644 --- a/src/include/prc_feat_const.nss +++ b/src/include/prc_feat_const.nss @@ -152,6 +152,9 @@ const int FEAT_EPIC_DIAMOND_DRAGON = 25115; const int FEAT_EPIC_CRUSADER = 25116; const int FEAT_EPIC_SWORDSAGE = 25117; const int FEAT_EPIC_WARBLADE = 25118; +const int FEAT_EPIC_LION_OF_TALISID = 25600; +const int FEAT_EPIC_VERDANT_LORD = 25618; + //:: Vile Martial Strike Expansion const int FEAT_VILE_MARTIAL_EAGLE_CLAW = 24800; @@ -195,6 +198,28 @@ const int FEAT_CHARMING_THE_ARROW = 25998; //:: Skill Based Feats const int FEAT_JUMP = 2884; +//:: Lion of Talisid +const int FEAT_LOT_LIONS_COURAGE = 25614; +const int FEAT_LOT_LIONS_POUNCE = 25615; +const int FEAT_LOT_LIONS_SWIFTNESS = 25616; +const int FEAT_LOT_LEONALS_ROAR = 25617; + +//::: Verdant Lord +const int FEAT_VL_EXPERT_INFUSION = 25634; +const int FEAT_VL_SUN_SUSTENANCE = 25635; +const int FEAT_VL_SPONTANEITY = 25636; +const int FEAT_VL_PLANT_FACILITY = 25637; +const int FEAT_VL_WILD_SHAPE_TREANT = 25638; +const int FEAT_VL_ANIMATE_TREE = 25639; +const int FEAT_VL_GAEAS_EMBRACE = 25640; + +//:: Masters of the Wild feats +const int FEAT_CREATE_INFUSION = 25960; +const int FEAT_MAGICAL_ARTISAN_CREATE_INFUSION = 25961; +const int FEAT_PLANT_DEFIANCE = 25992; +const int FEAT_PLANT_CONTROL = 25993; + + //:: Racial Feats const int FEAT_WEMIC_JUMP_8 = 4518; const int FEAT_URDINNIR_STONESKIN = 4644; @@ -782,6 +807,9 @@ const int FEAT_SUEL_IGNORE_SPELL_FAILURE = 2398; const int FEAT_SUEL_EXTENDED_SPELL = 2399; const int FEAT_SUEL_DISPELLING_STRIKE = 2400; +//:: Druid +const int FEAT_SPONT_SUMMON = 2372; + //Passive Feats const int FEAT_ETERNAL_FREEDOM = 4298; const int FEAT_INTUITIVE_ATTACK = 3166; @@ -1538,18 +1566,19 @@ const int FEAT_SELVETARMS_BLESSING = 2447; const int FEAT_RANGER_DUAL = 374; const int FEAT_CAMOUFLAGE = 4486; -//Exalted Feat -const int FEAT_SAC_VOW = 3388; -const int FEAT_VOW_OBED = 3389; -const int FEAT_EXALTED_TURNING = 3168; -const int FEAT_HAND_HEALER = 3167; -const int FEAT_NIMBUSLIGHT = 3165; -const int FEAT_HOLYRADIANCE = 3164; -const int FEAT_STIGMATA = 3163; -const int FEAT_SERVHEAVEN = 3355; -const int FEAT_RANGED_SMITE = 3356; -const int FEAT_VOW_PURITY = 5360; -const int FEAT_VOWOFPOVERTY = 26001; +//:: Exalted Feats +const int FEAT_SAC_VOW = 3388; +const int FEAT_VOW_OBED = 3389; +const int FEAT_EXALTED_TURNING = 3168; +const int FEAT_HAND_HEALER = 3167; +const int FEAT_NIMBUSLIGHT = 3165; +const int FEAT_HOLYRADIANCE = 3164; +const int FEAT_STIGMATA = 3163; +const int FEAT_SERVHEAVEN = 3355; +const int FEAT_RANGED_SMITE = 3356; +const int FEAT_VOW_PURITY = 5360; +const int FEAT_VOWOFPOVERTY = 26002; +const int FEAT_FAV_COMPANIONS = 25994; //Vile Feat const int FEAT_LICHLOVED = 3395; @@ -1868,12 +1897,12 @@ const int FEAT_SANCTIFY_MARTIAL_SICKLE = 3169; const int FEAT_SANCTIFY_MARTIAL_MINDBLADE = 3623; const int FEAT_SANCTIFY_MARTIAL_WHIP = 3596; const int FEAT_SANCTIFY_MARTIAL_TRIDENT = 3597; -const int FEAT_SANCTIFYKISTRIKE = 26002; -const int FEAT_HOLYKISTRIKE = 26003; -const int FEAT_FISTOFHEAVENS = 26004; -const int FEAT_VOWABSTINENCE = 26005; -const int FEAT_VOWCHASTITY = 26006; -const int FEAT_GIFTOFFAITH = 26007; +const int FEAT_SANCTIFYKISTRIKE = 26003; +const int FEAT_HOLYKISTRIKE = 26004; +const int FEAT_FISTOFHEAVENS = 26005; +const int FEAT_VOWABSTINENCE = 26006; +const int FEAT_VOWCHASTITY = 26007; +const int FEAT_GIFTOFFAITH = 26008; //heartwarder const int FEAT_CHARISMA_INC1 = 3230; @@ -3189,6 +3218,8 @@ const int FEAT_ETHEREAL = 4167; const int FEAT_TEMPLATE_ARCHLICH_MARKER = 22700; const int FEAT_TEMPLATE_ARCHLICH_TURN_UNDEAD = 22701; +const int FEAT_TEMPLATE_BAELNORN_MARKER = 22708; + const int FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL = 22601; const int FEAT_TEMPLATE_CELESTIAL_MARKER = 22602; const int FEAT_TEMPLATE_FIENDISH_SMITE_GOOD = 22603; @@ -3933,6 +3964,8 @@ const int FEAT_OPPORTUNISTIC_PIETY_HEAL = 5358; const int FEAT_OPPORTUNISTIC_PIETY_TURN = 5359; // Combat Maneuver Feats +const int FEAT_CM_CHARGE = 2823; +const int FEAT_CM_GRAPPLE = 3414; const int FEAT_CURLING_WAVE_STRIKE = 2809; const int FEAT_SIDESTEP_CHARGE = 3505; const int FEAT_POWERFUL_CHARGE = 3506; @@ -6203,6 +6236,38 @@ const int FEAT_SHINING_BLADE_SPELLCASTING_VASSAL = 19587; const int FEAT_SWIFT_WING_SPELLCASTING_VASSAL = 19588; const int FEAT_WARPRIEST_SPELLCASTING_VASSAL = 19589; +//:: Lion of Talisid marker feats +const int FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST = 25601; +const int FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC = 25602; +const int FEAT_LION_OF_TALISID_SPELLCASTING_DRUID = 25603; +const int FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL = 25604; +const int FEAT_LION_OF_TALISID_SPELLCASTING_HEALER = 25605; +const int FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW = 25606; +const int FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC = 25607; +const int FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER = 25608; +const int FEAT_LION_OF_TALISID_SPELLCASTING_RANGER = 25609; +const int FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN = 25610; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI = 25611; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SOL = 25612; +const int FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN = 25613; + +//:: Verdant Lord marker feats +const int FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST = 25619; +const int FEAT_VERDANT_LORD_SPELLCASTING_CLERIC = 25620; +const int FEAT_VERDANT_LORD_SPELLCASTING_DRUID = 25621; +const int FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL = 25622; +const int FEAT_VERDANT_LORD_SPELLCASTING_HEALER = 25623; +const int FEAT_VERDANT_LORD_SPELLCASTING_JOWAW = 25624; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTC = 25625; +const int FEAT_VERDANT_LORD_SPELLCASTING_KOTMC = 25626; +const int FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER = 25627; +const int FEAT_VERDANT_LORD_SPELLCASTING_PALADIN = 25628; +const int FEAT_VERDANT_LORD_SPELLCASTING_RANGER = 25629; +const int FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN = 25630; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOHEI = 25631; +const int FEAT_VERDANT_LORD_SPELLCASTING_SOL = 25632; +const int FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN = 25633; + //:: No spellcasting or invoking marker feats const int FEAT_ASMODEUS_SPELLCASTING_NONE = 19590; const int FEAT_TIAMAT_SPELLCASTING_NONE = 19591; diff --git a/src/include/prc_inc_castlvl.nss b/src/include/prc_inc_castlvl.nss index 876ac84..8336a62 100644 --- a/src/include/prc_inc_castlvl.nss +++ b/src/include/prc_inc_castlvl.nss @@ -575,8 +575,8 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) iReturnLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER); } - // Casting as a bard but don't have any levels in the class - if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + // Casting as a bard but don't have any levels in the class //:: Double-dipping? +/* if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { int nRace = GetRacialType(oCaster); @@ -584,7 +584,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) //otherwise use RHD instead of bard levels if(nRace == RACIAL_TYPE_GLOURA) iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY); - } + } */ //Spell Rage ability if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster) @@ -960,8 +960,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) } //:: End Bard Arcane PrC casting calculations - if(nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)"); + if(GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster); @@ -1065,7 +1067,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nArcane += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster); if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_FEY, oCaster)) + { nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey + Virtuoso PrC. Arcane caster level is "+IntToString(nArcane)+"."); + } if(GetHasFeat(FEAT_WWOC_SPELLCASTING_FEY, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster); @@ -1143,8 +1148,8 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_DIABOLIST_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster); - if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) - nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); + //if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster)) + //nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster); if(GetHasFeat(FEAT_EKNIGHT_SPELLCASTING_ASSASSIN, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster); @@ -3817,6 +3822,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_ARCHIVIST, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4143,7 +4151,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_CLERIC, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_CLERIC, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4253,7 +4264,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_DRUID, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_DRUID, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4365,10 +4379,13 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_FAVOURED_SOUL, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); - // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) - // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); + if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_FAVOURED_SOUL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -4474,6 +4491,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_HEALER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4581,6 +4601,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_JUSTICEWW, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_JUSTICEWW, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -4791,6 +4814,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -4896,7 +4922,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_NENTYAR_HUNTER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_NENTYAR_HUNTER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ @@ -5207,7 +5236,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */ if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_RANGER, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_RANGER, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster); @@ -5311,7 +5343,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_OASHAMAN, oCaster)) - nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_SHAMAN, oCaster); if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_OASHAMAN, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5524,6 +5559,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOHEI, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + // if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOHEI, oCaster)) // nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); @@ -5631,6 +5669,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster); + if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL, oCaster)) + nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster); + /* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOL, oCaster)) nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */ diff --git a/src/include/prc_inc_clsfunc.nss b/src/include/prc_inc_clsfunc.nss index 3a6c251..4d1ffcb 100644 --- a/src/include/prc_inc_clsfunc.nss +++ b/src/include/prc_inc_clsfunc.nss @@ -402,6 +402,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); @@ -482,6 +483,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; @@ -555,6 +557,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..df4a5b7 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; @@ -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 ); } @@ -1562,6 +1565,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; diff --git a/src/include/prc_inc_combmove.nss b/src/include/prc_inc_combmove.nss index b81aab4..d280dd1 100644 --- a/src/include/prc_inc_combmove.nss +++ b/src/include/prc_inc_combmove.nss @@ -1140,6 +1140,9 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO nPounce = TRUE; if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_CHUPOCLOPS_POUNCE) nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level @@ -2312,7 +2315,10 @@ void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE) if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5) nPounce = TRUE; if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT) - nPounce = TRUE; + nPounce = TRUE; + //:: Lion of Talisid + if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC)) + nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level diff --git a/src/include/prc_inc_core.nss b/src/include/prc_inc_core.nss index 30af518..099c3ac 100644 --- a/src/include/prc_inc_core.nss +++ b/src/include/prc_inc_core.nss @@ -462,7 +462,7 @@ int PRCGetSpellLevelForClass(int nSpell, int nClass) return nSpellLevel; } -// returns the spelllevel of nSpell as it can be cast by oCreature +// returns the spell circle level of nSpell as it can be cast by oCreature int PRCGetSpellLevel(object oCreature, int nSpell) { /*if (!PRCGetHasSpell(nSpell, oCreature)) @@ -605,7 +605,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) if(nSpellbookType == SPELLBOOK_TYPE_PREPARED) { nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; @@ -615,7 +615,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF) { nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j)); nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel); - if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); + if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount)); if(nCount > 0) { nUses += nCount; diff --git a/src/include/prc_inc_fork.nss b/src/include/prc_inc_fork.nss index 3e46b83..2b19f97 100644 --- a/src/include/prc_inc_fork.nss +++ b/src/include/prc_inc_fork.nss @@ -248,6 +248,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; @@ -318,6 +319,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; @@ -388,6 +390,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; @@ -458,7 +461,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; @@ -528,6 +532,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; @@ -598,6 +603,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; @@ -668,6 +674,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; @@ -729,6 +736,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 +795,7 @@ int GetWeaponSize(object oWeapon) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: @@ -823,6 +832,7 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize) case BASE_ITEM_GREATAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_QUARTERSTAFF: + //case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_ELVEN_COURTBLADE: diff --git a/src/include/prc_inc_function.nss b/src/include/prc_inc_function.nss index 93f7aa1..aa47614 100644 --- a/src/include/prc_inc_function.nss +++ b/src/include/prc_inc_function.nss @@ -108,8 +108,8 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_ALIENIST: sScript = "prc_alienist"; break; case CLASS_TYPE_ARCANE_DUELIST: sScript = "prc_arcduel"; break; case CLASS_TYPE_ARCHIVIST: sScript = "prc_archivist"; iData |= 0x01; break; - case CLASS_TYPE_ASSASSIN: iData |= 0x03; break; - case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; + case CLASS_TYPE_ASSASSIN: break; + //case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break; case CLASS_TYPE_BARD: iData |= 0x07; break; case CLASS_TYPE_BATTLESMITH: sScript = "prc_battlesmith"; break; case CLASS_TYPE_BEGUILER: iData |= 0x03; break; @@ -121,7 +121,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_BLIGHTLORD: sScript = "prc_blightlord"; break; case CLASS_TYPE_BLOODCLAW_MASTER: sScript = "tob_bloodclaw"; break; case CLASS_TYPE_BONDED_SUMMONNER: sScript = "prc_bondedsumm"; break; - case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x03; break; + case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x07; break; case CLASS_TYPE_CHILD_OF_NIGHT: sScript = "shd_childnight"; break; case CLASS_TYPE_COC: sScript = "prc_coc"; break; case CLASS_TYPE_COMBAT_MEDIC: sScript = "prc_cbtmed"; break; @@ -180,6 +180,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_LASHER: sScript = "prc_lasher"; break; case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread"; break; case CLASS_TYPE_LICH: sScript = "pnp_lich_level"; break; + case CLASS_TYPE_LION_OF_TALISID: sScript = "prc_lot"; break; case CLASS_TYPE_MAGEKILLER: sScript = "prc_magekill"; break; case CLASS_TYPE_MASTER_HARPER: sScript = "prc_masterh"; break; case CLASS_TYPE_MASTER_OF_NINE: sScript = "tob_masterofnine"; break; @@ -245,6 +246,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_TOTEM_RAGER: sScript = "moi_totemrager"; break; case CLASS_TYPE_TRUENAMER: sScript = "true_truenamer"; iData |= 0x01; break; case CLASS_TYPE_VASSAL: sScript = "prc_vassal"; break; + case CLASS_TYPE_VERDANT_LORD: sScript = "prc_verdantlord"; break; case CLASS_TYPE_VIGILANT: sScript = "prc_vigilant"; break; case CLASS_TYPE_WARBLADE: sScript = "tob_warblade"; iData |= 0x01; break; case CLASS_TYPE_WARCHIEF: sScript = "prc_warchief"; break; @@ -2264,6 +2266,8 @@ void FeatSpecialUsePerDay(object oPC) FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3); FeatUsePerDay(oPC, FEAT_SOD_DEATH_TOUCH, -1, (GetLevelByClass(CLASS_TYPE_SLAYER_OF_DOMIEL, oPC)+4)/4); FeatUsePerDay(oPC, FEAT_SUEL_DISPELLING_STRIKE, -1, (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) + 2) / 4); + FeatUsePerDay(oPC, FEAT_PLANT_CONTROL, ABILITY_CHARISMA, 3); + FeatUsePerDay(oPC, FEAT_PLANT_DEFIANCE, ABILITY_CHARISMA, 3); FeatDiabolist(oPC); FeatAlaghar(oPC); ShadowShieldUses(oPC); diff --git a/src/include/prc_inc_json.nss b/src/include/prc_inc_json.nss new file mode 100644 index 0000000..749c551 --- /dev/null +++ b/src/include/prc_inc_json.nss @@ -0,0 +1,750 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//::////////////////////////////////////////////// +//:: +/* + Library for json related functions. + +*/ +//:: +//::////////////////////////////////////////////// +//:: Script: prc_inc_json.nss +//:: Author: Jaysyn +//:: Created: 2025-08-14 12:52:32 +//::////////////////////////////////////////////// +#include "nw_inc_gff" +#include "inc_debug" + + +//::---------------------------------------------| +//:: Helper functions | +//::---------------------------------------------| + +//:: Function to calculate the maximum possible hitpoints for oCreature +int GetMaxPossibleHP(object oCreature) +{ + int nMaxHP = 0; // Stores the total maximum hitpoints + int i = 1; // Initialize position for class index + int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature); + + // Loop through each class position the creature may have, checking each class in turn + while (TRUE) + { + // Get the class ID at position i + int nClassID = GetClassByPosition(i, oCreature); + + // If class is invalid (no more classes to check), break out of loop + if (nClassID == CLASS_TYPE_INVALID) + break; + + // Get the number of levels in this class + int nClassLevels = GetLevelByClass(nClassID, oCreature); + + // Get the row index of the class in classes.2da by using class ID as the row index + int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClassID)); + + // Add maximum HP for this class (Hit Die * number of levels in this class) + nMaxHP += nClassLevels * nHitDie; + + // Move to the next class position + i++; + } + + nMaxHP += nConb * GetHitDice(oCreature); + + return nMaxHP; +} + +// Returns how many feats a creature should gain when its HD increases +int CalculateFeatsFromHD(int nOriginalHD, int nNewHD) +{ + // HD increase + int nHDIncrease = nNewHD - nOriginalHD; + + if (nHDIncrease <= 0) + return 0; // No new feats if HD did not increase + + // D&D 3E: 1 feat per 3 HD + int nBonusFeats = nHDIncrease / 3; + + return nBonusFeats; +} + +// Returns how many stat boosts a creature needs based on its HD +int GetStatBoostsFromHD(int nCreatureHD, int nModiferCap) +{ + // Make sure we don't get negative boosts + int nBoosts = (40 - nCreatureHD) / 4; + if (nBoosts < 0) + { + nBoosts = 0; + } + return nBoosts; +} + +// Struct to hold size modifiers +struct SizeModifiers +{ + int strMod; + int dexMod; + int conMod; + int naturalAC; + int attackBonus; + int dexSkillMod; +}; + +//::---------------------------------------------| +//:: JSON functions | +//::---------------------------------------------| + +//:: Returns the integer value of a VarTable entry named sVarName, or 0 if not found. +int json_GetLocalIntFromVarTable(json jCreature, string sVarName) +{ + json jVarTable = GffGetList(jCreature, "VarTable"); + if (jVarTable == JsonNull()) + return 0; + + int nCount = JsonGetLength(jVarTable); + int i; + for (i = 0; i < nCount; i++) + { + json jEntry = JsonArrayGet(jVarTable, i); + if (jEntry == JsonNull()) continue; + + // Get the Name field using GFF functions + json jName = GffGetString(jEntry, "Name"); + if (jName == JsonNull()) continue; + string sName = JsonGetString(jName); + + if (sName == sVarName) + { + // Get the Type field to verify it's an integer + json jType = GffGetDword(jEntry, "Type"); + if (jType != JsonNull()) + { + int nType = JsonGetInt(jType); + if (nType == 1) // Type 1 = integer + { + // Get the Value field using GFF functions + json jValue = GffGetInt(jEntry, "Value"); + if (jValue == JsonNull()) return 0; + return JsonGetInt(jValue); + } + } + } + } + + return 0; +} + +//:: Returns the total Hit Dice from a JSON creature GFF. +int json_GetCreatureHD(json jGff) +{ + int nHD = 0; + + json jClasses = GffGetList(jGff, "ClassList"); + if (jClasses == JsonNull()) + return 0; + + int nCount = JsonGetLength(jClasses); + int i; + for (i = 0; i < nCount; i = i + 1) + { + json jClass = JsonArrayGet(jClasses, i); + if (jClass == JsonNull()) + continue; + + json jLevel = GffGetShort(jClass, "ClassLevel"); // Use GffGetShort, not GffGetField + if (jLevel != JsonNull()) + { + int nLevel = JsonGetInt(jLevel); + nHD += nLevel; + } + } + + if (nHD <= 0) nHD = 1; + return nHD; +} + +//:: Reads ABILITY_TO_INCREASE from creature's VarTable and applies stat boosts based on increased HD +json json_ApplyAbilityBoostFromHD(json jCreature, int nOriginalHD, int nModifierCap) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Get the ability to increase from VarTable + int nAbilityToIncrease = json_GetLocalIntFromVarTable(jCreature, "ABILITY_TO_INCREASE"); + if (nAbilityToIncrease < 0 || nAbilityToIncrease > 5) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Invalid ABILITY_TO_INCREASE value: " + IntToString(nAbilityToIncrease)); + return jCreature; // Invalid ability index + } + + // Calculate total current HD from ClassList + json jClassList = GffGetList(jCreature, "ClassList"); + if (jClassList == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get ClassList"); + return jCreature; + } + + int nCurrentTotalHD = 0; + int nClassCount = JsonGetLength(jClassList); + int i; + + for (i = 0; i < nClassCount; i++) + { + json jClass = JsonArrayGet(jClassList, i); + if (jClass != JsonNull()) + { + json jClassLevel = GffGetShort(jClass, "ClassLevel"); + if (jClassLevel != JsonNull()) + { + nCurrentTotalHD += JsonGetInt(jClassLevel); + } + } + } + + if (nCurrentTotalHD <= 0) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No valid Hit Dice found"); + return jCreature; + } + + // Calculate stat boosts based on crossing level thresholds + // Characters get stat boosts at levels 4, 8, 12, 16, 20, etc. + int nOriginalBoosts = nOriginalHD / 4; // How many boosts they already had + int nCurrentBoosts = nCurrentTotalHD / 4; // How many they should have now + int nBoosts = nCurrentBoosts - nOriginalBoosts; // Additional boosts to apply + + if (nBoosts <= 0) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No boosts needed (Original boosts: " + IntToString(nOriginalBoosts) + ", Current boosts: " + IntToString(nCurrentBoosts) + ")"); + return jCreature; + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Applying " + IntToString(nBoosts) + " boosts to ability " + IntToString(nAbilityToIncrease) + " for HD increase from " + IntToString(nOriginalHD) + " to " + IntToString(nCurrentTotalHD)); + + // Determine which ability to boost and apply the increases + string sAbilityField; + switch (nAbilityToIncrease) + { + case 0: sAbilityField = "Str"; break; + case 1: sAbilityField = "Dex"; break; + case 2: sAbilityField = "Con"; break; + case 3: sAbilityField = "Int"; break; + case 4: sAbilityField = "Wis"; break; + case 5: sAbilityField = "Cha"; break; + default: + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Unknown ability index: " + IntToString(nAbilityToIncrease)); + return jCreature; + } + + // Get current ability score + json jCurrentAbility = GffGetByte(jCreature, sAbilityField); + if (jCurrentAbility == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get " + sAbilityField + " score"); + return jCreature; + } + + int nCurrentScore = JsonGetInt(jCurrentAbility); + int nNewScore = nCurrentScore + nBoosts; + + // Clamp to valid byte range + if (nNewScore < 1) nNewScore = 1; + if (nNewScore > 255) nNewScore = 255; + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Increasing " + sAbilityField + " from " + IntToString(nCurrentScore) + " to " + IntToString(nNewScore)); + + // Apply the ability score increase + jCreature = GffReplaceByte(jCreature, sAbilityField, nNewScore); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to update " + sAbilityField); + return JsonNull(); + } + + if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Successfully applied ability boosts"); + return jCreature; +} + +//:: Adjust a skill by its ID (more efficient than name lookup) +json json_AdjustCreatureSkillByID(json jCreature, int nSkillID, int nMod) +{ + // Get the SkillList + json jSkillList = GffGetList(jCreature, "SkillList"); + if (jSkillList == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get SkillList"); + return jCreature; + } + + // Check if we have enough skills in the list + int nSkillCount = JsonGetLength(jSkillList); + if (nSkillID >= nSkillCount) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Skill ID " + IntToString(nSkillID) + " exceeds skill list length " + IntToString(nSkillCount)); + return jCreature; + } + + // Get the skill struct at the correct index + json jSkill = JsonArrayGet(jSkillList, nSkillID); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get skill at index " + IntToString(nSkillID)); + return jCreature; + } + + // Get current rank + json jRank = GffGetByte(jSkill, "Rank"); + if (jRank == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get Rank for skill ID " + IntToString(nSkillID)); + return jCreature; + } + + int nCurrentRank = JsonGetInt(jRank); + int nNewRank = nCurrentRank + nMod; + + // Clamp to valid range + if (nNewRank < 0) nNewRank = 0; + if (nNewRank > 255) nNewRank = 255; + + // Update the rank in the skill struct + jSkill = GffReplaceByte(jSkill, "Rank", nNewRank); + if (jSkill == JsonNull()) + { + if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to replace Rank for skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + + // Replace the skill in the array + jSkillList = JsonArraySet(jSkillList, nSkillID, jSkill); + + // Replace the SkillList in the creature + jCreature = GffReplaceList(jCreature, "SkillList", jSkillList); + + return jCreature; +} + +//:: Reads FutureFeat1..FutureFeatN from the template's VarTable and appends them to FeatList if missing. +json json_AddFeatsFromCreatureVars(json jCreature, int nOriginalHD) +{ + if (jCreature == JsonNull()) + return jCreature; + + // Calculate current total HD + int nCurrentHD = json_GetCreatureHD(jCreature); + int nAddedHD = nCurrentHD - nOriginalHD; + + if (nAddedHD <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional HD to process (Current: " + IntToString(nCurrentHD) + ", Original: " + IntToString(nOriginalHD) + ")"); + return jCreature; + } + + // Calculate how many feats the creature should get based on added HD + // Characters get a feat at levels 1, 3, 6, 9, 12, 15, 18, etc. + // For added levels, we need to check what feat levels they cross + int nOriginalFeats = (nOriginalHD + 2) / 3; // Feats from original HD + int nCurrentFeats = (nCurrentHD + 2) / 3; // Feats from current HD + int nNumFeats = nCurrentFeats - nOriginalFeats; // Additional feats earned + + if (nNumFeats <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional feats earned from " + IntToString(nAddedHD) + " added HD"); + return jCreature; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Processing " + IntToString(nNumFeats) + " feats for " + IntToString(nAddedHD) + " added HD (Original: " + IntToString(nOriginalHD) + ", Current: " + IntToString(nCurrentHD) + ")"); + + // Get or create FeatList + json jFeatArray = GffGetList(jCreature, "FeatList"); + if (jFeatArray == JsonNull()) + jFeatArray = JsonArray(); + + int nOriginalFeatCount = JsonGetLength(jFeatArray); + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount)); + + int nAdded = 0; + int i = 1; + int nMaxIterations = 100; // Safety valve + int nIterations = 0; + + while (nAdded < nNumFeats && nIterations < nMaxIterations) + { + nIterations++; + string sVarName = "FutureFeat" + IntToString(i); + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Checking " + sVarName); + + int nFeat = json_GetLocalIntFromVarTable(jCreature, sVarName); + + if (nFeat <= 0) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: " + sVarName + " not found or invalid"); + i++; + continue; + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Found " + sVarName + " = " + IntToString(nFeat)); + + // Check if feat already exists + int bHasFeat = FALSE; + int nFeatCount = JsonGetLength(jFeatArray); + int j; + + for (j = 0; j < nFeatCount; j++) + { + json jFeatStruct = JsonArrayGet(jFeatArray, j); + if (jFeatStruct != JsonNull()) + { + json jFeatValue = GffGetWord(jFeatStruct, "Feat"); + if (jFeatValue != JsonNull() && JsonGetInt(jFeatValue) == nFeat) + { + bHasFeat = TRUE; + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Feat " + IntToString(nFeat) + " already exists"); + break; + } + } + } + + // Insert if missing + if (!bHasFeat) + { + json jNewFeat = JsonObject(); + jNewFeat = JsonObjectSet(jNewFeat, "__struct_id", JsonInt(1)); + jNewFeat = GffAddWord(jNewFeat, "Feat", nFeat); + + if (jNewFeat == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to create feat struct for feat " + IntToString(nFeat)); + break; + } + + jFeatArray = JsonArrayInsert(jFeatArray, jNewFeat); + nAdded++; + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Added feat " + IntToString(nFeat) + " (" + IntToString(nAdded) + "/" + IntToString(nNumFeats) + ")"); + } + + i++; + + // Safety break if we've checked too many variables + if (i > 100) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Safety break - checked too many FutureFeat variables"); + break; + } + } + + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Completed. Added " + IntToString(nAdded) + " feats in " + IntToString(nIterations) + " iterations"); + + // Save back the modified FeatList only if we added something + if (nAdded > 0) + { + jCreature = GffReplaceList(jCreature, "FeatList", jFeatArray); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to replace FeatList"); + return JsonNull(); + } + } + + return jCreature; +} + +//:: Get the size of a JSON array +int json_GetArraySize(json jArray) +{ + int iSize = 0; + while (JsonArrayGet(jArray, iSize) != JsonNull()) + { + iSize++; + } + return iSize; +} + +//:: Directly modifies oCreature's Base Natural AC if iNewAC is higher. +//:: +json json_UpdateBaseAC(json jCreature, int iNewAC) +{ + //json jBaseAC = GffGetByte(jCreature, "Creature/value/NaturalAC/value"); + json jBaseAC = GffGetByte(jCreature, "NaturalAC"); + + if (jBaseAC == JsonNull()) + { + return JsonNull(); + } + else if (JsonGetInt(jBaseAC) > iNewAC) + { + return jCreature; + } + else + { + jCreature = GffReplaceByte(jCreature, "NaturalAC", iNewAC); + + return jCreature; + } +} + +//:: Directly modifies jCreature's Challenge Rating. +//:: This is useful for most XP calculations. +json json_UpdateCR(json jCreature, int nBaseCR, int nCRMod) +{ + int nNewCR; + +//:: Add CRMod to current CR + nNewCR = nBaseCR + nCRMod; + +//:: Modify Challenge Rating + jCreature = GffReplaceFloat(jCreature, "ChallengeRating", IntToFloat(nNewCR)); + + return jCreature; +} + +//:: Directly modifies ability scores in a creature's JSON GFF. +//:: +json json_UpdateTemplateStats(json jCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, + int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ + int iCurrent; + + // STR + if (!GffGetFieldExists(jCreature, "Str", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Str", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Str")); + jCreature = GffReplaceByte(jCreature, "Str", iCurrent + iModStr); + + // DEX + if (!GffGetFieldExists(jCreature, "Dex", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Dex", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Dex")); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrent + iModDex); + + // CON + if (!GffGetFieldExists(jCreature, "Con", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Con", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Con")); + jCreature = GffReplaceByte(jCreature, "Con", iCurrent + iModCon); + + // INT + if (!GffGetFieldExists(jCreature, "Int", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Int", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Int")); + jCreature = GffReplaceByte(jCreature, "Int", iCurrent + iModInt); + + // WIS + if (!GffGetFieldExists(jCreature, "Wis", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Wis", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Wis")); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrent + iModWis); + + // CHA + if (!GffGetFieldExists(jCreature, "Cha", GFF_FIELD_TYPE_BYTE)) + jCreature = GffAddByte(jCreature, "Cha", 10); + iCurrent = JsonGetInt(GffGetByte(jCreature, "Cha")); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrent + iModCha); + + return jCreature; +} + +//:: Directly modifies oCreature's ability scores. +//:: +json json_UpdateCreatureStats(json jCreature, object oBaseCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, int iModInt = 0, int iModWis = 0, int iModCha = 0) +{ +//:: Retrieve and modify ability scores + int iCurrentStr = GetAbilityScore(oBaseCreature, ABILITY_STRENGTH); + int iCurrentDex = GetAbilityScore(oBaseCreature, ABILITY_DEXTERITY); + int iCurrentCon = GetAbilityScore(oBaseCreature, ABILITY_CONSTITUTION); + int iCurrentInt = GetAbilityScore(oBaseCreature, ABILITY_INTELLIGENCE); + int iCurrentWis = GetAbilityScore(oBaseCreature, ABILITY_WISDOM); + int iCurrentCha = GetAbilityScore(oBaseCreature, ABILITY_CHARISMA); + + jCreature = GffReplaceByte(jCreature, "Str", iCurrentStr + iModStr); + jCreature = GffReplaceByte(jCreature, "Dex", iCurrentDex + iModDex); + jCreature = GffReplaceByte(jCreature, "Con", iCurrentCon + iModCon); + jCreature = GffReplaceByte(jCreature, "Int", iCurrentInt + iModInt); + jCreature = GffReplaceByte(jCreature, "Wis", iCurrentWis + iModWis); + jCreature = GffReplaceByte(jCreature, "Cha", iCurrentCha + iModCha); + + return jCreature; +} + +//:: Increases a creature's Hit Dice in its JSON GFF data by nAmount +json json_AddHitDice(json jCreature, int nAmount) +{ + if (jCreature == JsonNull() || nAmount <= 0) + return jCreature; + + // Get the ClassList + json jClasses = GffGetList(jCreature, "ClassList"); + if (jClasses == JsonNull() || JsonGetLength(jClasses) == 0) + return jCreature; + + // Grab the first class entry + json jFirstClass = JsonArrayGet(jClasses, 0); + + // Only touch ClassLevel; do NOT modify Class type + json jCurrentLevel = GffGetShort(jFirstClass, "ClassLevel"); + int nCurrentLevel = JsonGetInt(jCurrentLevel); + int nNewLevel = nCurrentLevel + nAmount; + + // Replace ClassLevel only + jFirstClass = GffReplaceShort(jFirstClass, "ClassLevel", nNewLevel); + + // Put modified class back into the array + jClasses = JsonArraySet(jClasses, 0, jFirstClass); + + // Replace ClassList in the creature JSON + jCreature = GffReplaceList(jCreature, "ClassList", jClasses); + + return jCreature; +} + +//:: Adjusts a creature's size by nSizeChange (-4 to +4) and updates ability scores accordingly. +json json_AdjustCreatureSize(json jCreature, int nSizeDelta) +{ + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Entering function. nSizeDelta=" + IntToString(nSizeDelta)); + + if (jCreature == JsonNull() || nSizeDelta == 0) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Exiting: jCreature is null or nSizeDelta is 0"); + return jCreature; + } + + // Get Appearance_Type using GFF functions + json jAppearanceType = GffGetWord(jCreature, "Appearance_Type"); + if (jAppearanceType == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to get Appearance_Type"); + return jCreature; + } + + int nAppearance = JsonGetInt(jAppearanceType); + int nCurrentSize = StringToInt(Get2DAString("appearances", "Size", nAppearance)); + + // Default to Medium (4) if invalid + if (nCurrentSize < 0 || nCurrentSize > 8) nCurrentSize = 4; + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Appearance_Type =" + IntToString(nAppearance) + ", Size =" + IntToString(nCurrentSize)); + + int nSteps = nSizeDelta; + + // Calculate modifiers based on size change + int strMod = nSteps * 4; + int dexMod = nSteps * -1; + int conMod = nSteps * 2; + int naturalAC = nSteps * 1; + int dexSkillMod = nSteps * -2; + + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Applying stat modifiers: STR=" + IntToString(strMod) + + " DEX=" + IntToString(dexMod) + + " CON=" + IntToString(conMod)); + + // Update ability scores using GFF functions with error checking + json jStr = GffGetByte(jCreature, "Str"); + if (jStr != JsonNull()) + { + int nNewStr = JsonGetInt(jStr) + strMod; + if (nNewStr < 1) nNewStr = 1; + if (nNewStr > 255) nNewStr = 255; + + jCreature = GffReplaceByte(jCreature, "Str", nNewStr); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Str"); + return JsonNull(); + } + } + + json jDex = GffGetByte(jCreature, "Dex"); + if (jDex != JsonNull()) + { + int nNewDex = JsonGetInt(jDex) + dexMod; + if (nNewDex < 1) nNewDex = 1; + if (nNewDex > 255) nNewDex = 255; + + jCreature = GffReplaceByte(jCreature, "Dex", nNewDex); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Dex"); + return JsonNull(); + } + } + + json jCon = GffGetByte(jCreature, "Con"); + if (jCon != JsonNull()) + { + int nNewCon = JsonGetInt(jCon) + conMod; + if (nNewCon < 1) nNewCon = 1; + if (nNewCon > 255) nNewCon = 255; + + jCreature = GffReplaceByte(jCreature, "Con", nNewCon); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Con"); + return JsonNull(); + } + } + + // Update Natural AC + json jNaturalAC = GffGetByte(jCreature, "NaturalAC"); + if (jNaturalAC != JsonNull()) + { + int nCurrentNA = JsonGetInt(jNaturalAC); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Current NaturalAC: " + IntToString(nCurrentNA)); + + int nNewNA = nCurrentNA + naturalAC; + if (nNewNA < 0) nNewNA = 0; + if (nNewNA > 255) nNewNA = 255; + + jCreature = GffReplaceByte(jCreature, "NaturalAC", nNewNA); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update NaturalAC"); + return JsonNull(); + } + } + + // Adjust all Dexterity-based skills by finding them in skills.2da + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX-based skills"); + + int nSkillID = 0; + while (TRUE) + { + string sKeyAbility = Get2DAString("skills", "KeyAbility", nSkillID); + + // Break when we've reached the end of skills + if (sKeyAbility == "") + break; + + // If this skill uses Dexterity, adjust it + if (sKeyAbility == "DEX") + { + string sSkillLabel = Get2DAString("skills", "Label", nSkillID); + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX skill: " + sSkillLabel + " (ID: " + IntToString(nSkillID) + ")"); + + jCreature = json_AdjustCreatureSkillByID(jCreature, nSkillID, dexSkillMod); + if (jCreature == JsonNull()) + { + if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed adjusting skill ID " + IntToString(nSkillID)); + return JsonNull(); + } + } + + nSkillID++; + } + + if(DEBUG) DoDebug("json_AdjustCreatureSize completed successfully"); + return jCreature; +} + + +//:: Test void +//:: void main (){} \ No newline at end of file diff --git a/src/include/prc_inc_material.nss b/src/include/prc_inc_material.nss index f69e26d..dc050aa 100644 --- a/src/include/prc_inc_material.nss +++ b/src/include/prc_inc_material.nss @@ -16,26 +16,28 @@ const int MATERIAL_TYPE_UNKNOWN = 0; const int MATERIAL_TYPE_BONE = 1; const int MATERIAL_TYPE_CERAMIC = 2; const int MATERIAL_TYPE_CRYSTAL = 3; -const int MATERIAL_TYPE_FABRIC = 4; +const int MATERIAL_TYPE_FIBER = 4; const int MATERIAL_TYPE_LEATHER = 5; const int MATERIAL_TYPE_METAL = 6; const int MATERIAL_TYPE_PAPER = 7; const int MATERIAL_TYPE_ROPE = 8; const int MATERIAL_TYPE_STONE = 9; const int MATERIAL_TYPE_WOOD = 10; +const int MATERIAL_TYPE_BOTANICAL = 11; const string MATERIAL_TYPE_NAME_INVALID = ""; const string MATERIAL_TYPE_NAME_UNKNOWN = "Unknown"; const string MATERIAL_TYPE_NAME_BONE = "Bone"; const string MATERIAL_TYPE_NAME_CERAMIC = "Ceramic"; const string MATERIAL_TYPE_NAME_CRYSTAL = "Crystal"; -const string MATERIAL_TYPE_NAME_FABRIC = "Fabric"; +const string MATERIAL_TYPE_NAME_FIBER = "Fiber"; const string MATERIAL_TYPE_NAME_LEATHER = "Leather"; const string MATERIAL_TYPE_NAME_METAL = "Metal"; const string MATERIAL_TYPE_NAME_PAPER = "Paper"; const string MATERIAL_TYPE_NAME_ROPE = "Rope"; const string MATERIAL_TYPE_NAME_STONE = "Stone"; const string MATERIAL_TYPE_NAME_WOOD = "Wood"; +const string MATERIAL_TYPE_NAME_BOTANICAL = "Bontanical"; //:: Material Itemproperty Constants //:://////////////////////////////////////////////////////////////////////////////// @@ -163,7 +165,8 @@ const int IP_MATERIAL_OBSIDIAN = 140; const int IP_MATERIAL_BAMBOO = 141; const int IP_MATERIAL_POTTERY = 142; const int IP_MATERIAL_GLASSTEEL = 143; -const int IP_NUM_MATERIALS = 143; +const int IP_MATERIAL_HERB = 144; +const int IP_NUM_MATERIALS = 144; const string IP_MATERIAL_NAME_INVALID = ""; const string IP_MATERIAL_NAME_UNKNOWN = "Unknown"; @@ -288,6 +291,7 @@ const string IP_MATERIAL_NAME_OBSIDIAN = "Obsidian"; const string IP_MATERIAL_NAME_BAMBOO = "Bamboo"; const string IP_MATERIAL_NAME_POTTERY = "Pottery"; const string IP_MATERIAL_NAME_GLASSTEEL = "Glassteel"; +const string IP_MATERIAL_NAME_HERB = "Herbs"; //:://///////////////////////////////////////////////////////////// // GetMaterialName( int iMaterialType, int bLowerCase = FALSE) @@ -428,6 +432,7 @@ string GetMaterialName( int iMaterialType, int bLowerCase = FALSE) case IP_MATERIAL_BAMBOO: sName = IP_MATERIAL_NAME_BAMBOO; break; case IP_MATERIAL_POTTERY: sName = IP_MATERIAL_NAME_POTTERY; break; case IP_MATERIAL_GLASSTEEL: sName = IP_MATERIAL_NAME_GLASSTEEL; break; + case IP_MATERIAL_HERB: sName = IP_MATERIAL_NAME_HERB; break; default: return ""; } @@ -573,6 +578,7 @@ int GetIPMaterial( string sMaterialName) else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_BAMBOO)) return IP_MATERIAL_BAMBOO; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_POTTERY)) return IP_MATERIAL_POTTERY; else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_GLASSTEEL)) return IP_MATERIAL_GLASSTEEL; + else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_HERB)) return IP_MATERIAL_HERB; return IP_MATERIAL_INVALID; } @@ -806,6 +812,9 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_DRAKE_IVORY ) return MATERIAL_TYPE_BONE; + else if ( nMaterial == IP_MATERIAL_HERB ) + return MATERIAL_TYPE_BOTANICAL; + else if ( nMaterial == IP_MATERIAL_ELUKIAN_CLAY || nMaterial == IP_MATERIAL_POTTERY ) return MATERIAL_TYPE_CERAMIC; @@ -814,7 +823,7 @@ int GetMaterialType(int nMaterial) || nMaterial == IP_MATERIAL_COTTON || nMaterial == IP_MATERIAL_SILK || nMaterial == IP_MATERIAL_WOOL ) - return MATERIAL_TYPE_FABRIC; + return MATERIAL_TYPE_FIBER; else if ( nMaterial == IP_MATERIAL_GEM || nMaterial == IP_MATERIAL_GEM_ALEXANDRITE diff --git a/src/include/prc_inc_skills.nss b/src/include/prc_inc_skills.nss index bbca299..0674604 100644 --- a/src/include/prc_inc_skills.nss +++ b/src/include/prc_inc_skills.nss @@ -115,11 +115,11 @@ int PerformJump(object oPC, location lLoc, int bDoKnockDown = TRUE) iBonus = 4; } } - /*if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) + if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) { bIsRunningJump = TRUE; - iBonus = 10; - } */ + //iBonus = 10; //:: This is granted in the stance. + } // PnP rules are height * 6 for run and height * 2 for jump. // I can't get height so that is assumed to be 6. // Changed maxed jump distance because the NwN distance is rather short @@ -374,6 +374,12 @@ int PRCIsFlying(object oCreature) if(GetRacialType(oCreature) == RACIAL_TYPE_GLOURA) bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_AVARIEL) + bFlying = TRUE; + + if(GetRacialType(oCreature) == RACIAL_TYPE_FEYRI) + bFlying = TRUE; if(GetRacialType(oCreature) == RACIAL_TYPE_SPIRETOPDRAGON) bFlying = TRUE; diff --git a/src/include/prc_inc_spells.nss b/src/include/prc_inc_spells.nss index 19e73d7..18c0efa 100644 --- a/src/include/prc_inc_spells.nss +++ b/src/include/prc_inc_spells.nss @@ -20,6 +20,11 @@ /* Function prototypes */ ////////////////////////////////////////////////// + + +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature); + //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25); @@ -376,23 +381,53 @@ const int TYPE_DIVINE = -2; /* Function definitions */ ////////////////////////////////////////////////// + +// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise +int GetIsSubradialSpell(int nSpellID) +{ + string sMaster = Get2DACache("spells", "Master", nSpellID); + + // If the Master column is numeric, this spell is a subradial of that master + if (sMaster != "" && sMaster != "****") + { + return TRUE; + } + + return FALSE; +} + +// Returns the masterspell SpellID for a subradial spell. +int GetMasterSpellFromSubradial(int nSpellID) +{ + string sMaster = Get2DAString("spells", "Master", nSpellID); + + if (sMaster != "****") + { + return StringToInt(sMaster); + } + + return -1; // No master +} + + + int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF) { int iTemp; // is it arcane, divine or neither? if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD) { - if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs + if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs iTemp = GetArcanePRCLevels(oCaster, nClass); } else if(GetIsDivineClass(nClass, oCaster)) { - if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs - iTemp = GetDivinePRCLevels(oCaster, nClass); + if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs + iTemp = GetDivinePRCLevels(oCaster, nClass); } else // a non-caster class or a PrC { - return 0; + return 0; } // add the caster class levels return iTemp += GetLevelByClass(nClass, oCaster); @@ -412,7 +447,9 @@ int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF { int nClassLvl; int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8; - int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl; + int nClass1Lvl = 0, nClass2Lvl = 0, nClass3Lvl = 0, nClass4Lvl = 0, + nClass5Lvl = 0, nClass6Lvl = 0, nClass7Lvl = 0, nClass8Lvl = 0; + nClass1 = GetClassByPosition(1, oCaster); nClass2 = GetClassByPosition(2, oCaster); @@ -2223,6 +2260,78 @@ int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF) return nTotalHD; } +//:: Calculates total Shield AC bonuses from all sources +int GetTotalShieldACBonus(object oCreature) +{ + int nShieldBonus = 0; + object oItem; + + // Check left hand for shield + oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + if (GetIsObjectValid(oItem)) + { + int nBaseItem = GetBaseItemType(oItem); + if (nBaseItem == BASE_ITEM_SMALLSHIELD || + nBaseItem == BASE_ITEM_LARGESHIELD || + nBaseItem == BASE_ITEM_TOWERSHIELD) + { + nShieldBonus += GetItemACValue(oItem); + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC, bonus = " + IntToString(nShieldBonus)+"."); + } + } + + // Check creature weapon slots for shield AC bonus + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature); + if (GetIsObjectValid(oItem)) + nShieldBonus += GetItemACValue(oItem); + + // Add shield AC bonuses from magical effects + effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + int nACType = GetEffectInteger(eEffect, 0); + int nACAmount = GetEffectInteger(eEffect, 1); + + if(GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && nACType == AC_SHIELD_ENCHANTMENT_BONUS) + { + if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC effect, bonus = " + IntToString(nACAmount)+"."); + nShieldBonus += nACAmount; + } + + eEffect = GetNextEffect(oCreature); + } + return nShieldBonus; +} + + + + // Add shield AC bonuses from magical effects +/* effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + if (GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && + GetEffectInteger(eEffect, 1) == AC_SHIELD_ENCHANTMENT_BONUS) + { + int nMod = GetEffectInteger(eEffect, 0); + int nType = GetEffectInteger(eEffect, 1); + nShieldBonus += GetEffectInteger(eEffect, 0); + string s = "Found AC effect: bonus = " + IntToString(nMod) + ", type = " + IntToString(nType); + SendMessageToPC(GetFirstPC(), s); + } + eEffect = GetNextEffect(oCreature); + } + + return nShieldBonus; +}*/ +// //:: Handles psuedo-Foritifcation void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) { @@ -2275,7 +2384,7 @@ void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25) IPSafeAddItemProperty(oHide, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB)); } } - +// // wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too // should also find and decrement metamagics for newspellbooks diff --git a/src/include/prc_inc_switch.nss b/src/include/prc_inc_switch.nss index 4913e3d..b2c7160 100644 --- a/src/include/prc_inc_switch.nss +++ b/src/include/prc_inc_switch.nss @@ -70,6 +70,8 @@ 43 PRC_CRAFTING_BASE_ITEMS int 1 44 PRC_XP_USE_SIMPLE_LA int 1 45 PRC_XP_USE_SIMPLE_RACIAL_HD int 1 +46 PRC_CREATE_INFUSION_CASTER_LEVEL int 1 +47 PRC_CREATE_INFUSION_OPTIONAL_HERBS int 0 */ /* This variable MUST be updated with every new version of the PRC!!! */ @@ -1952,6 +1954,18 @@ const string PRC_CRAFT_ROD_CASTER_LEVEL = "PRC_CRAFT_ROD_CASTER_LEVE */ const string PRC_CRAFT_STAFF_CASTER_LEVEL = "PRC_CRAFT_STAFF_CASTER_LEVEL"; +/* + * As above, except it applies to herbal infusions + */ +const string PRC_CREATE_INFUSION_CASTER_LEVEL = "PRC_CREATE_INFUSION_CASTER_LEVEL"; + +/* + * Builder's Option: Enables the optional PnP herbs for creating infusions. + * Each herb is keyed to a spell circle level & spell school as shown on pg. 33 + * of the Master's of the Wild sourcebook. + */ +const string PRC_CREATE_INFUSION_OPTIONAL_HERBS = "PRC_CREATE_INFUSION_OPTIONAL_HERBS"; + /* * Characters with a crafting feat always have the appropriate base item in their inventory */ @@ -1961,45 +1975,52 @@ const string PRC_CRAFTING_BASE_ITEMS = "PRC_CRAFTING_BASE_ITEMS"; * Max level of spells brewed into potions * defaults to 3 */ -const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +//const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL"; +const string PRC_X2_BREWPOTION_MAXLEVEL = "PRC_X2_BREWPOTION_MAXLEVEL"; /* * cost modifier of spells brewed into poitions * defaults to 50 */ -const string X2_CI_BREWPOTION_COSTMODIFIER = "X2_CI_BREWPOTION_COSTMODIFIER"; +const string PRC_X2_BREWPOTION_COSTMODIFIER = "PRC_X2_BREWPOTION_COSTMODIFIER"; /* * cost modifier of spells scribed into scrolls * defaults to 25 */ -const string X2_CI_SCRIBESCROLL_COSTMODIFIER = "X2_CI_SCRIBESCROLL_COSTMODIFIER"; +const string PRC_X2_SCRIBESCROLL_COSTMODIFIER = "PRC_X2_SCRIBESCROLL_COSTMODIFIER"; + +/* + * cost modifier of spells infused into herbs + * defaults to 25 + */ +const string PRC_X2_CREATEINFUSION_COSTMODIFIER = "PRC_X2_CREATEINFUSION_COSTMODIFIER"; /* * Max level of spells crafted into wands * defaults to 4 */ -const string X2_CI_CRAFTWAND_MAXLEVEL = "X2_CI_CRAFTWAND_MAXLEVEL"; +const string PRC_X2_CRAFTWAND_MAXLEVEL = "PRC_X2_CRAFTWAND_MAXLEVEL"; /* * cost modifier of spells crafted into wands * defaults to 750 */ -const string X2_CI_CRAFTWAND_COSTMODIFIER = "X2_CI_CRAFTWAND_COSTMODIFIER"; +const string PRC_X2_CRAFTWAND_COSTMODIFIER = "PRC_X2_CRAFTWAND_COSTMODIFIER"; /* * cost modifier of spells crafted into rods * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTROD_COSTMODIFIER = "X2_CI_CRAFTROD_COSTMODIFIER"; +const string PRC_X2_CRAFTROD_COSTMODIFIER = "PRC_X2_CRAFTROD_COSTMODIFIER"; /* * cost modifier of spells crafted into staffs * note that adding a second spell costs 75% and 3 or more costs 50% * defaults to 750 */ -const string X2_CI_CRAFTSTAFF_COSTMODIFIER = "X2_CI_CRAFTSTAFF_COSTMODIFIER"; +const string PRC_X2_CRAFTSTAFF_COSTMODIFIER = "PRC_X2_CRAFTSTAFF_COSTMODIFIER"; /** * Allows the use of arbitrary itemproperties and uses NWN item costs diff --git a/src/include/prc_inc_turning.nss b/src/include/prc_inc_turning.nss index 5504819..6c819d4 100644 --- a/src/include/prc_inc_turning.nss +++ b/src/include/prc_inc_turning.nss @@ -14,17 +14,6 @@ /* Function prototypes */ ////////////////////////////////////////////////// - - - - - - - - - - - //gets the number of class levels that count for turning int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TURN_UNDEAD); @@ -191,6 +180,20 @@ int GetIsTurnOrRebuke(object oTarget, int nTurnType, int nTargetRace) break; } + case SPELL_PLANT_DEFIANCE: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_TURN; + + break; + } + case SPELL_PLANT_CONTROL: + { + if(nTargetRace == RACIAL_TYPE_PLANT) + nReturn = ACTION_REBUKE; + + break; + } case SPELL_TURN_PLANT: { // Plant domain rebukes or commands plants @@ -383,6 +386,13 @@ int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TUR if (nTurnType == SPELL_OPPORTUNISTIC_PIETY_TURN) return GetLevelByClass(CLASS_TYPE_FACTOTUM, oCaster); + + if (nTurnType == SPELL_PLANT_DEFIANCE || nTurnType == SPELL_PLANT_CONTROL) + { + int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); + + return nDivineLvl; + } //Baelnorn & Archlich adds all class levels. if(GetLevelByClass(CLASS_TYPE_BAELNORN, oCaster) || GetHasFeat(FEAT_TEMPLATE_ARCHLICH_MARKER, oCaster)) //:: Archlich diff --git a/src/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss index 401b323..9dcf65a 100644 --- a/src/include/prc_inc_wpnrest.nss +++ b/src/include/prc_inc_wpnrest.nss @@ -40,13 +40,31 @@ int IsProficient(object oPC, int nBaseItem) case BASE_ITEM_CLUB: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC); + + case BASE_ITEM_HEAVYCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW, oPC); + + case BASE_ITEM_LIGHTCROSSBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW, oPC); case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) - || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC); case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC) @@ -152,10 +170,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 +320,185 @@ int GetWeaponProfFeatByType(int nBaseType) { switch(nBaseType) { - case BASE_ITEM_SHORTSWORD: - return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; + case BASE_ITEM_CLUB: + return FEAT_WEAPON_PROFICIENCY_CLUB; + + case BASE_ITEM_QUARTERSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; - case BASE_ITEM_LONGSWORD: - return FEAT_WEAPON_PROFICIENCY_LONGSWORD; + case BASE_ITEM_MAGICSTAFF: + return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF; + + case BASE_ITEM_DAGGER: + return FEAT_WEAPON_PROFICIENCY_DAGGER; - case BASE_ITEM_BATTLEAXE: - return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; + case BASE_ITEM_HEAVYCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW; - case BASE_ITEM_BASTARDSWORD: - return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; + case BASE_ITEM_LIGHTCROSSBOW: + return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW; + + case BASE_ITEM_SHORTSWORD: + return FEAT_WEAPON_PROFICIENCY_SHORTSWORD; - case BASE_ITEM_LIGHTFLAIL: - return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; + case BASE_ITEM_LONGSWORD: + return FEAT_WEAPON_PROFICIENCY_LONGSWORD; - case BASE_ITEM_WARHAMMER: - return FEAT_WEAPON_PROFICIENCY_WARHAMMER; + case BASE_ITEM_BATTLEAXE: + return FEAT_WEAPON_PROFICIENCY_BATTLEAXE; - case BASE_ITEM_LONGBOW: - return FEAT_WEAPON_PROFICIENCY_LONGBOW; + case BASE_ITEM_BASTARDSWORD: + return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD; - case BASE_ITEM_LIGHTMACE: - return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + case BASE_ITEM_LIGHTFLAIL: + return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL; - case BASE_ITEM_HALBERD: - return FEAT_WEAPON_PROFICIENCY_HALBERD; + case BASE_ITEM_WARHAMMER: + return FEAT_WEAPON_PROFICIENCY_WARHAMMER; - case BASE_ITEM_SHORTBOW: + case BASE_ITEM_LONGBOW: + return FEAT_WEAPON_PROFICIENCY_LONGBOW; + + case BASE_ITEM_LIGHTMACE: + return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE; + + case BASE_ITEM_HALBERD: + return FEAT_WEAPON_PROFICIENCY_HALBERD; + + case BASE_ITEM_SHORTBOW: return FEAT_WEAPON_PROFICIENCY_SHORTBOW; - case BASE_ITEM_TWOBLADEDSWORD: + case BASE_ITEM_TWOBLADEDSWORD: return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD; - case BASE_ITEM_GREATSWORD: + case BASE_ITEM_GREATSWORD: return FEAT_WEAPON_PROFICIENCY_GREATSWORD; - case BASE_ITEM_GREATAXE: + case BASE_ITEM_GREATAXE: return FEAT_WEAPON_PROFICIENCY_GREATAXE; - case BASE_ITEM_DART: + case BASE_ITEM_DART: return FEAT_WEAPON_PROFICIENCY_DART; - case BASE_ITEM_DIREMACE: + case BASE_ITEM_DIREMACE: return FEAT_WEAPON_PROFICIENCY_DIRE_MACE; - case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_DOUBLEAXE: return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE; - case BASE_ITEM_HEAVYFLAIL: + case BASE_ITEM_HEAVYFLAIL: return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL; - case BASE_ITEM_LIGHTHAMMER: + case BASE_ITEM_LIGHTHAMMER: return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER; - case BASE_ITEM_HANDAXE: + case BASE_ITEM_HANDAXE: return FEAT_WEAPON_PROFICIENCY_HANDAXE; - case BASE_ITEM_KAMA: + case BASE_ITEM_KAMA: return FEAT_WEAPON_PROFICIENCY_KAMA; - case BASE_ITEM_KATANA: + case BASE_ITEM_KATANA: return FEAT_WEAPON_PROFICIENCY_KATANA; - case BASE_ITEM_KUKRI: + case BASE_ITEM_KUKRI: return FEAT_WEAPON_PROFICIENCY_KUKRI; - case BASE_ITEM_MORNINGSTAR: + case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR; - case BASE_ITEM_RAPIER: + case BASE_ITEM_RAPIER: return FEAT_WEAPON_PROFICIENCY_RAPIER; - case BASE_ITEM_SCIMITAR: + case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_SCIMITAR; - case BASE_ITEM_SCYTHE: + case BASE_ITEM_SCYTHE: return FEAT_WEAPON_PROFICIENCY_SCYTHE; - case BASE_ITEM_SHORTSPEAR: + case BASE_ITEM_SHORTSPEAR: return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR; - case BASE_ITEM_SHURIKEN: + case BASE_ITEM_SHURIKEN: return FEAT_WEAPON_PROFICIENCY_SHURIKEN; - case BASE_ITEM_SICKLE: + case BASE_ITEM_SICKLE: return FEAT_WEAPON_PROFICIENCY_SICKLE; - case BASE_ITEM_SLING: + case BASE_ITEM_SLING: return FEAT_WEAPON_PROFICIENCY_SLING; - case BASE_ITEM_THROWINGAXE: + case BASE_ITEM_THROWINGAXE: return FEAT_WEAPON_PROFICIENCY_THROWING_AXE; - case BASE_ITEM_CSLASHWEAPON: + case BASE_ITEM_CSLASHWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CPIERCWEAPON: + case BASE_ITEM_CPIERCWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CBLUDGWEAPON: + case BASE_ITEM_CBLUDGWEAPON: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_CSLSHPRCWEAP: + case BASE_ITEM_CSLSHPRCWEAP: return FEAT_WEAPON_PROFICIENCY_CREATURE; - case BASE_ITEM_TRIDENT: + case BASE_ITEM_TRIDENT: return FEAT_WEAPON_PROFICIENCY_TRIDENT; - case BASE_ITEM_DWARVENWARAXE: + case BASE_ITEM_DWARVENWARAXE: return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE; - case BASE_ITEM_WHIP: + case BASE_ITEM_WHIP: return FEAT_WEAPON_PROFICIENCY_WHIP; - case BASE_ITEM_ELVEN_LIGHTBLADE: + case BASE_ITEM_ELVEN_LIGHTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE; - case BASE_ITEM_ELVEN_THINBLADE: + case BASE_ITEM_ELVEN_THINBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE; - case BASE_ITEM_ELVEN_COURTBLADE: + case BASE_ITEM_ELVEN_COURTBLADE: return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE; - case BASE_ITEM_HEAVY_PICK: + case BASE_ITEM_HEAVY_PICK: return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK; - case BASE_ITEM_LIGHT_PICK: + case BASE_ITEM_LIGHT_PICK: return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK; - case BASE_ITEM_SAI: + case BASE_ITEM_SAI: return FEAT_WEAPON_PROFICIENCY_SAI; - case BASE_ITEM_NUNCHAKU: + case BASE_ITEM_NUNCHAKU: return FEAT_WEAPON_PROFICIENCY_NUNCHAKU; - case BASE_ITEM_FALCHION: + case BASE_ITEM_FALCHION: return FEAT_WEAPON_PROFICIENCY_FALCHION; - case BASE_ITEM_SAP: + case BASE_ITEM_SAP: return FEAT_WEAPON_PROFICIENCY_SAP; - case BASE_ITEM_KATAR: + case BASE_ITEM_KATAR: return FEAT_WEAPON_PROFICIENCY_KATAR; - case BASE_ITEM_HEAVY_MACE: + case BASE_ITEM_HEAVY_MACE: return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE; - case BASE_ITEM_MAUL: + case BASE_ITEM_MAUL: return FEAT_WEAPON_PROFICIENCY_MAUL; - case BASE_ITEM_DOUBLE_SCIMITAR: + case BASE_ITEM_DOUBLE_SCIMITAR: return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR; - case BASE_ITEM_GOAD: + case BASE_ITEM_GOAD: return FEAT_WEAPON_PROFICIENCY_GOAD; - case BASE_ITEM_EAGLE_CLAW: + case BASE_ITEM_EAGLE_CLAW: return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW; - default: - return FEAT_WEAPON_PROFICIENCY_SIMPLE; + default: + return FEAT_WEAPON_PROFICIENCY_SIMPLE; } return 0; diff --git a/src/include/prc_ipfeat_const.nss b/src/include/prc_ipfeat_const.nss index a1829be..d419f0b 100644 --- a/src/include/prc_ipfeat_const.nss +++ b/src/include/prc_ipfeat_const.nss @@ -1206,11 +1206,12 @@ const int IP_CONST_FEAT_REGENERATION_5 = 24820; const int IP_CONST_FEAT_SCENT = 24821; const int IP_CONST_FEAT_GIANT_RACIAL_TYPE = 24822; -const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich -const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; -const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; -const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; -const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; +const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich +const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402; +const int IP_CONST_FEAT_TEMPLATE_BAELNORN_MARKER = 16409; //:: Baelnorn +const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823; +const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824; +const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_BLESS = 16403; //:: Saint //const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_GUIDANCE = 16404; const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_RESISTANCE = 16405; diff --git a/src/include/prc_misc_const.nss b/src/include/prc_misc_const.nss index 0575811..b083a8e 100644 --- a/src/include/prc_misc_const.nss +++ b/src/include/prc_misc_const.nss @@ -29,6 +29,10 @@ const int BASE_ITEM_CRAFTED_STAFF = 201; const int BASE_ITEM_ELVEN_LIGHTBLADE = 202; const int BASE_ITEM_ELVEN_THINBLADE = 203; const int BASE_ITEM_ELVEN_COURTBLADE = 204; +const int BASE_ITEM_CRAFT_SCEPTER = 249; +const int BASE_ITEM_MAGIC_SCEPTER = 250; +const int BASE_ITEM_MUNDANE_HERB = 252; +const int BASE_ITEM_INFUSED_HERB = 253; //::////////////////////////////////////////////// //:: Player Health Const diff --git a/src/include/prc_nui_com_inc.nss b/src/include/prc_nui_com_inc.nss new file mode 100644 index 0000000..bf9bc51 --- /dev/null +++ b/src/include/prc_nui_com_inc.nss @@ -0,0 +1,530 @@ +#include "prc_nui_consts" +#include "inc_newspellbook" +#include "psi_inc_psifunc" +#include "inc_lookups" +#include "nw_inc_nui" + +// +// GetCurrentSpellLevel +// Gets the current spell level the class can achieve at the current +// caster level (ranging from 0-9) +// +// Arguments: +// nClass:int the ClassID +// nLevel:int the caster level +// +// Returns: +// int the circle the class can achieve currently +// +int GetCurrentSpellLevel(int nClass, int nLevel); + +// +// GetMaxSpellLevel +// Gets the highest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest circle that can be achieved +// +int GetMaxSpellLevel(int nClass); + +// +// GetMinSpellLevel +// Gets the lowest possible circle the class can achieve (from 0-9) +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the lowest circle that can be achieved +// +int GetMinSpellLevel(int nClass); + +// +// GetHighestLevelPossibleInClass +// Given a class Id this will determine what the max level of a class can be +// achieved +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int the highest possible level the class can achieve +// +int GetHighestLevelPossibleInClass(int nClass); + +// +// GetClassSpellbookFile +// Gets the class 2da spellbook/ability for the given class Id +// +// Arguments: +// nClass:int the classID +// +// Returns: +// string the 2da file name for the spell/abilities of the ClassID +// +string GetClassSpellbookFile(int nClass); + +// +// GetBinderSpellToFeatDictionary +// Sets up the Binder Spell Dictionary that is used to match a binder's vestige +// to their feat. This is constructed based off the binder's known location of +// their feat and spell ranges in the base 2das respectivly. After constructing +// this it will be saved to the player locally as a cached result since we do +// not need to call this again. +// +// Argument: +// oPlayer:object the player +// +// Returns: +// json:Dictionary a dictionary of mapping between the SpellID +// and the FeatID of a vestige ability +// +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); + +// +// GetSpellLevelIcon +// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns +// into "ir_cantrips" +// +// Arguments: +// spellLevel:int the spell level we want the icon for +// +// Returns: +// string the spell level icon +// +string GetSpellLevelIcon(int spellLevel); + +// +// GetSpellLevelToolTip +// Gets the spell level tool tip text based on the int spell level provided (i.e. +// 0 turns into "Cantrips") +// +// Arguments: +// spellLevel:int the spell level we want the tooltip for +// +// Returns: +// string the spell level toop tip +// +string GetSpellLevelToolTip(int spellLevel); + +// +// GetSpellIcon +// Gets the spell icon based off the spellId, or featId supplied +// +// Arguments: +// nClass:int the class Id +// featId:int the featId we can use the icon for +// spellId:int the spell Id we want the icon for +// +// Returns: +// json:String the string of the icon we want. +// +json GetSpellIcon(int spellId, int featId=0, int nClass=0); +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0); + +// +// GreyOutButton +// Takes NUI Button along with it's width and height and greys it out it with a drawn +// colored rectangle to represent it's not been selected or not valid. +// +// Arguments: +// jButton:json the NUI Button +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the NUI button greyed out +// +json GreyOutButton(json jButton, float w, float h); + +// +// CreateGreyOutRectangle +// Creates a grey out rectangle for buttons +// +// Arguments: +// w:float the width of the button +// h:float the height of the button +// +// Returns: +// json the transparant black rectangle +// +json CreateGreyOutRectangle(float w, float h); + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0); +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF); + +int GetCurrentSpellLevel(int nClass, int nLevel) +{ + int currentLevel = nLevel; + + // ToB doesn't have a concept of spell levels, but still match up to it + if(nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_SHADOWCASTER) + { + return 9; + } + + + // Binders don't really have a concept of spell level + if (nClass == CLASS_TYPE_BINDER + || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle + return 1; + + //Shadowsmith has no concept of spell levels + if (nClass == CLASS_TYPE_SHADOWSMITH) + return 2; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + return 4; + + // Spont casters have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); + return maxLevel; + } + else + { + // everyone else uses this + string spellLevel2da = GetAMSKnownFileName(nClass); + + currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da + + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND) + currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; + + int totalLevel = Get2DARowCount(spellLevel2da); + + // in case we somehow go over bounds just don't :) + if (currentLevel >= totalLevel) + currentLevel = totalLevel - 1; + + //Psionics have MaxPowerLevel as their column name + string columnName = "MaxPowerLevel"; + + //Invokers have MaxInvocationLevel + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + columnName = "MaxInvocationLevel"; + + // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range + if (nClass == CLASS_TYPE_TRUENAMER) + { + columnName = "EvolvingMind"; + spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + columnName = "VestigeLvl"; + spellLevel2da = "cls_bind_binder"; + } + + // ToB doesn't have a concept of this, but we don't care. + + int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); + return maxLevel; + } +} + +int GetMinSpellLevel(int nClass) +{ + // again sponts have their own function + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); + } + else + { + if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_WARMIND + || nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_BINDER) + return 1; + + return GetCurrentSpellLevel(nClass, 1); + } + +} + +int GetMaxSpellLevel(int nClass) +{ + if (nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_PSION) + return 9; + if (nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WARMIND) + return 5; + if (nClass == CLASS_TYPE_PSYWAR) + return 6; + + return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); +} + +int GetHighestLevelPossibleInClass(int nClass) +{ + string sFile; + + //sponts have their spells in the classes.2da + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = Get2DACache("classes", "SpellGainTable", nClass); + } + else + { + // everyone else uses this + sFile = GetAMSKnownFileName(nClass); + + if (nClass == CLASS_TYPE_TRUENAMER) + { + sFile = "cls_true_maxlvl"; //has a different 2da we want to look at + } + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "cls_bind_binder"; + } + } + + return Get2DARowCount(sFile); +} + +string GetClassSpellbookFile(int nClass) +{ + string sFile; + // Spontaneous casters use a specific file name structure + if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + sFile = GetFileForClass(nClass); + } + // everyone else uses this structure + else + { + sFile = GetAMSDefinitionFileName(nClass); + + if (nClass == CLASS_TYPE_BINDER) + { + sFile = "vestiges"; + } + } + + return sFile; +} + +string GetSpellLevelIcon(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "ir_cantrips"; + case 1: return "ir_level1"; + case 2: return "ir_level2"; + case 3: return "ir_level3"; + case 4: return "ir_level4"; + case 5: return "ir_level5"; + case 6: return "ir_level6"; + case 7: return "ir_level789"; + case 8: return "ir_level789"; + case 9: return "ir_level789"; + } + + return ""; +} + +string GetSpellLevelToolTip(int spellLevel) +{ + switch (spellLevel) + { + case 0: return "Cantrips"; + case 1: return "Level 1"; + case 2: return "Level 2"; + case 3: return "Level 3"; + case 4: return "Level 4"; + case 5: return "Level 5"; + case 6: return "Level 6"; + case 7: return "Level 7"; + case 8: return "Level 8"; + case 9: return "Level 9"; + } + + return ""; +} + + +json GetSpellIcon(int spellId,int featId=0,int nClass=0) +{ + // Binder's spells don't have the FeatID on the spells.2da, so we have to use + // the mapping we constructed to get it. + if (nClass == CLASS_TYPE_BINDER) + { + json binderDict = GetBinderSpellToFeatDictionary(); + int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); + return JsonString(Get2DACache("feat", "Icon", featId)); + } + + if (featId) + return JsonString(Get2DACache("feat", "Icon", featId)); + + int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId)); + + // if this is a sub radial spell, then we use spell's icon instead + if (masterSpellID) + return JsonString(Get2DACache("spells", "IconResRef", spellId)); + + // the FeatID holds the accurate spell icon, not the SpellID + int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId)); + + return JsonString(Get2DACache("feat", "Icon", nFeatID)); +} + +string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0) +{ + if ((nClass == CLASS_TYPE_SHADOWSMITH + || nClass == CLASS_TYPE_SHADOWCASTER) && spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (nClass == CLASS_TYPE_TRUENAMER && featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + if (realSpellID) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID))); + if (spellId) + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + if (featId) + return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId))); + + return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); +} + +json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) +{ + // a dictionary of + json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); + // if this hasn't been created, create it now. + if (binderDict == JsonNull()) + binderDict = JsonObject(); + else + return binderDict; + + // the starting row for binder spells + int spellIndex = 19070; + // the starting row for binder feats + int featIndex = 9030; + //the end of the binder spells/feats + while (spellIndex <= 19156 && featIndex <= 9104) + { + // get the SpellID tied to the feat + int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); + // if the spellID matches the current index, then this is the spell + // attached to the feat + if (spellID == spellIndex) + { + binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); + + // move to next spell/feat + featIndex++; + spellIndex++; + } + // else we have reached a subdial spell + else + { + // loop through until we reach back at spellID + while (spellIndex < spellID) + { + int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); + + // add the sub radial to the dict, tied to the master's FeatID + int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); + binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); + + spellIndex++; + } + + + // some feats overlap the same FeatID, can cause this to get stuck. + // if it happens then move on + if (spellIndex > spellID) + featIndex++; + } + } + + // cache the result + SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); + return binderDict; +} + +json GreyOutButton(json jButton, float w, float h) +{ + json retValue = jButton; + + json jBorders = JsonArray(); + jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h)); + + return NuiDrawList(jButton, JsonBool(FALSE), jBorders); +} + +json CreateGreyOutRectangle(float w, float h) +{ + // set the points of the button shape + json jPoints = JsonArray(); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(h)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(w)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0)); + + return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints); +} + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0) +{ + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId); + SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass); + ExecuteScript("prc_nui_dsc_view", oPlayer); +} + +void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF) +{ + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR); + DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR); +} + diff --git a/src/include/prc_nui_consts.nss b/src/include/prc_nui_consts.nss index 0cb0efa..e1e9c5c 100644 --- a/src/include/prc_nui_consts.nss +++ b/src/include/prc_nui_consts.nss @@ -110,4 +110,49 @@ const string NUI_PRC_PA_TEXT_BIND = "nui_prc_pa_text_bind"; // Left Button Enabled Bind for Power Attack NUI const string NUI_PRC_PA_LEFT_BUTTON_ENABLED_BIND = "leftButtonEnabled"; // Right Button Enabled Bind for Power Attack NUI -const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; \ No newline at end of file +const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; + +////////////////////////////////////////////////// +// // +// NUI Level Up // +// // +////////////////////////////////////////////////// + +const string NUI_LEVEL_UP_WINDOW_ID = "prcLevelUpNui"; + +const string NUI_LEVEL_UP_SPELL_CIRCLE_BUTTON_BASEID = "NuiLevelUpCircleButton_"; +const string NUI_LEVEL_UP_SPELL_BUTTON_BASEID = "NuiLevelUpSpellButton_"; +const string NUI_LEVEL_UP_SPELL_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_BUTTON_BASEID = "NuiLevelUpChosenSpellButton_"; +const string NUI_LEVEL_UP_SPELL_CHOSEN_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledChosenSpellButton_"; +const string NUI_LEVEL_UP_DONE_BUTTON = "NuiLevelUpDoneButton"; +const string NUI_LEVEL_UP_RESET_BUTTON = "NuiLevelUpResetButton"; + +const string NUI_LEVEL_UP_SELECTED_CLASS_VAR = "NUILevelUpSelectedClass"; +const string NUI_LEVEL_UP_SELECTED_CIRCLE_VAR = "NUILevelUpSelectedCircle"; +const string NUI_LEVEL_UP_KNOWN_SPELLS_VAR = "NUILevelUpKnownSpells"; +const string NUI_LEVEL_UP_CHOSEN_SPELLS_VAR = "NUILevelUpChosenSpells"; +const string NUI_LEVEL_UP_EXPANDED_KNOW_LIST_VAR = "NUILevelUpExpKnowList"; +const string NUI_LEVEL_UP_POWER_LIST_VAR = "NUILevelUpPowerList"; +const string NUI_LEVEL_UP_DISCIPLINE_INFO_VAR = "GetDisciplineInfoObjectCache_"; +const string NUI_LEVEL_UP_SPELLID_LIST_VAR = "NUILevelUpSpellIDList_"; +const string NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR = "NUIRemainingChoicesCache"; +const string NUI_LEVEL_UP_RELEARN_LIST_VAR = "NUILevelUpRelearnList"; +const string NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR = "NUILevelUpArchivistNewSpellsList"; + +const string NUI_LEVEL_UP_EXPANDED_CHOICES_VAR = "NUIExpandedChoices"; +const string NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR = "NUIEpicExpandedChoices"; + +const int NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT = 6; + +const string NUI_LEVEL_UP_MANEUVER_TOTAL = "ManeuverTotal"; +const string NUI_LEVEL_UP_STANCE_TOTAL = "StanceTotal"; + +const string NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR = "GetSpellListObjectCache_"; +const string NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR = "GetInvokerKnownListObjectCache_"; + +const string NUI_SPELL_DESCRIPTION_FEATID_VAR = "NUISpellDescriptionFeatID"; +const string NUI_SPELL_DESCRIPTION_CLASSID_VAR = "NUISpellDescriptionClassID"; +const string NUI_SPELL_DESCRIPTION_SPELLID_VAR = "NUISpellDescriptionSpellID"; +const string NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR = "NUISpellDescriptionRealSpellID"; + diff --git a/src/include/prc_nui_lv_inc.nss b/src/include/prc_nui_lv_inc.nss new file mode 100644 index 0000000..bc10b28 --- /dev/null +++ b/src/include/prc_nui_lv_inc.nss @@ -0,0 +1,3339 @@ +//:://///////////////////////////////////////////// +//:: PRC Level Up NUI +//:: prc_nui_lv_inc +//::////////////////////////////////////////////// +/* + This is the logic for the Level Up NUI, holding all the functions needed for + the NUI to operate properly and allow leveling up in different classes. +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 20.06.2005 +//::////////////////////////////////////////////// + +#include "prc_nui_com_inc" +#include "tob_inc_tobfunc" +#include "tob_inc_moveknwn" +#include "inv_inc_invfunc" +#include "shd_inc_mystknwn" +#include "shd_inc_shdfunc" +#include "true_inc_truknwn" +#include "true_inc_trufunc" + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetSpellListObject +// Gets the JSON Object representation of a class's spellbook 2da. This function +// will cache it's result to the object given to it to avoid further calculations +// and will not clear itself since it does not change. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's spellbook Ids. +// +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's known spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's known spellbook Ids. +// +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetKnownSpellListObject +// Gets the JSON Object representation of a player's chosen spell list. This function +// will temporarily cache it's result to the object given to avoid further calculations. +// However this should be cleared after done using the level up screen or reset. +// +// Arguments: +// nClass:int the ClassID +// oPC:Object the player +// +// Returns: +// Json:Dictionary a dictionary of each circle's chosen spellbook Ids. +// +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF); + +// +// ShouldAddSpellToSpellButtons +// Given a classId and a spellbookId, if the player knows the spell already we +// should not add the spell, otherwise we should +// +// Arguments: +// nClass:int Class ID +// spellbookId:int the spell book ID +// oPC:object the player +// +// Returns: +// int:Boolean TRUE if spell should be added, FALSE otherwise +// +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// OpenNUILevelUpWindow +// Opens the Level Up NUI window for the provided class +// +// Arguments: +// nClass:int the ClassID +// +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF); + +// +// CloseNUILevelUpWindow +// Closes the NUI Level Up Window if its open +// +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF); + +// +// GetTrueClassType +// Gets the true class Id for a provided class Id, mostly for RHD and for +// ToB prestige classes +// +// Arguments: +// nClass:int classId +// +// Returns: +// int the true classId based off nClass +// +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingSpellChoices +// Gets the remaining spell choices for a class at the given circle by checking its +// chosen spells and comparing it against the total spells allowed. This value +// is cached on the player and cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// circleLevel:int the circle being checked +// +// Returns: +// int the amount of choices left at the circle +// +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF); + +// +// ShouldSpellButtonBeEnabled +// Checks whether a spell button should be enabled either because all choices have +// been made, replacing spells isn't allowed, or for various other reasons +// +// Arguments: +// nClass:int class id +// circleLevel:int the chosen circle +// spellbookId:int the chosen spell +// +// Returns: +// int:Boolean TRUE if spell button should be enabled, FALSE otherwise +// +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellToChosenList +// Adds spell to the chosen spells list +// +// Arguments: +// nClass:int the classId +// spellbookId:int the spellbook Id +// spellCircle:int the current circle of the spell +// +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// RemoveSpellFromChosenList +// Removes a spell from the chosen spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// spellCircle:int the circle of the spell +// +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF); + +// +// LearnSpells +// gives the player the spells they want to learn based off of the chosen spell +// list in a stored variable +// +// Arguments: +// nClass:int the classId +// +void LearnSpells(int nClass, object oPC=OBJECT_SELF); + +// +// RemoveSpells +// removes spells from the player that they may know currently but aren't selected +// based off lists in stored variables +// +// Arguments: +// nClass:int the classId +// +void RemoveSpells(int nClass, object oPC=OBJECT_SELF); + +// +// FinishLevelUp +// Finishes level up NUI by removing spells, learning spells, clearing cache, then closing the NUI +// +// Arguments: +// nClass:int the class id +// +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF); + +// +// ClearLevelUpNUICaches +// Clears the cache (stored local variables) for the level up NUI so it is +// ready to be used for a new level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object this is stored under +// +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF); + +// +// SpellIsWithinObject +// checks whether a spell is within a JSON Object structure used by the remaining +// spells object and known spells object, following this structure +// { +// "circleLevel:int": [ 1,2,3...,spellId], +// ... +// } +// +// Arguments +// nClass:int classId +// spellbookId:int the spellbook Id +// circleLevel:int the chosen circle of the spell +// spellList;JsonObject the spell list object being checked +// +// Returns: +// int:Boolean TRUE if it is in the object, FALSE otherwise +// +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF); + +// +// IsLevelUpNUIOpen +// Checks if the Level Up NUI is open for the player or not +// +// Arguments: +// oPC:object the player object +// +// Returns: +// int:Boolean TRUE if it is, FALSE otherwise +// +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF); + +// +// IsClassAllowedToUseLevelUpNUI +// Is the provided class allowed to use the level up NUI +// +// Arguments: +// nClass:int class id +// +// Returns: +// int:Boolean TRUE if it can, FALSE otherwise +// +int IsClassAllowedToUseLevelUpNUI(int nClass); + +// +// EnabledChosenButton +// determines if a chosen spell button should be enabled or not. It may not due to +// class restrictions, replacing is not enabled, or other reason +// +// Arguments: +// nClass:int the class id +// spellbookId: the spellbook Id +// circleLevel: the spell's circle +// +// Returns: +// int:Boolean TRUE if it should be enabled, FALSE otherwise +// +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF); + +// +// ResetChoices +// Action for the Level Up NUI's 'Reset' button, resets choices by clearing the cache of +// the user so their choices are forgotten and they can start over. +// +// Arguments: +// oPC:object the player object +// +void ResetChoices(object oPC=OBJECT_SELF); + +// +// RemoveSpellKnown +// Removes a spell from a player based off class id. This is for classes that +// aren't spont casters where we have to go in and adjust persistant arrays +// to say if a spell is known or not. +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// oPC:object the player object +// nList:int the list we are removing the spell from (extra invocations or expanded knowledge) +// +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0); + +// +// GetSpellIDsKnown +// Gets the SpellIDs list of the given class and list and returns it as a JsonObject following this structure +// { +// "spellId:int": TRUE, +// ... +// } +// +// This is to keep lookups at O(1) processing time. This value is cached and is +// cleared when the player finishes level up +// +// Arguments: +// nClass:int class id +// oPC:object the player object +// nList:int the list we are checking if provided (extra invocations or expanded knowledge) +// +// Returns: +// JsonObject the list of spell ids the class knows in JsonObject format +// +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0); + +// +// ReasonForDisabledSpell +// Provides the reason for why a spell choice is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// ReasonForDisabledChosen +// Provides the reason for why a chosen spell button is disabled +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// string the reason for the disabled button, empty string otherwise +// +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetExpandedChoicesList +// Gets the epic expanded choices list for a class (the list of expanded knowledge or +// extra invocations). It follows this structure +// +// { +// "spellId:int": TRUE, +// ... +// } +// This is cached to reduce process times and is cleared everytime the window is refreshed/closed +// +// Arguments: +// nClass:int the class id +// +// Returns: +// JsonObject the object representation of the expanded choices +// +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingExpandedChoices +// Gets the remaining expanded choices for a class based off list, comparing the +// total number of choices allowed and the total number chosen +// +// Arguments: +// nClass: class id +// nList: the list we are checking (extra invocations/expanded knowledge) +// +// Returns: +// int the amount of choices left +// +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF); +// +// IsSpellInExpandedChoices +// tells if a spell is in the expanded choices list or not +// +// Arguments: +// nClass:int class id +// nList:int the list we are checking (extra invocations/expanded knowledge) +// spellId:int the spell id (not the spellbook id) +// +// Returns +// int:Boolean TRUE if it is a expanded choice, FALSE otherwise +// +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF); + +// +// GetChosenReplaceListObject +// The chosen list of spells we wish to replace for PnP replacing if Bioware replacing +// is disabled. This is cached and is cleared when the player is finished leveling +// or resets their choices +// +// Arguments: +// oPC:object the player +// +// Returns: +// json the list of spells chosen to replace +// +json GetChosenReplaceListObject(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// IsExpKnowledgePower +// checks if a spell is a expanded knowledge spell +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook Id +// +// Returns: +// int:Boolean TRUE if the spell is a expanded knowledge spell, FALSE otherwise +// +int IsExpKnowledgePower(int nClass, int spellbookId); + +// +// GetExpKnowledgePowerListRequired +// Tells what list the spell should be added to based on if it was added to the +// expanded choices or epic expanded choices list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook Id +// +// Returns: +// int -1 for the expanded knowledge list, -2 for the epic expanded knowledge +// list, 0 if just add it to the normal class list +// +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetCurrentPowerList +// Gets the current chosen powers list. This is cached and is cleared when the +// player either finishs leveling up or resets. +// +// Arguments: +// oPC:object the player object +// +// Returns: +// JsonArray the list of chosen powers wanting to learn +// +json GetCurrentPowerList(object oPC=OBJECT_SELF); + +// +// ShouldAddPower +// Tells if the power should be added to the list of choices or not. It may not +// be added because its an expanded knowledge choice and you have no more expanded +// knowledge slots, or it may be a restricted spell like psions list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if it should be added, FALSE otherwise +// +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// LearnPowers +// learns the list of chosen powers for the player based off their chosen power list +// +// Arguments: +// nClass:int class id +// oPC:object the player object where stored variables are +// +void LearnPowers(int nClass, object oPC=OBJECT_SELF); + +// +// GetMaxPowerLevelForClass +// gets the max power level for the player based off their level and the class's +// known 2da +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the max power level (circle) the player can achieve on that class +// +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingPowerChoices +// Gets the remaining power choices the character has at the given chosen circle/power level +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle/power level +// oPC:object the player +// extra:int should we add the expanded knowledge choices or not +// +// Returns: +// int the number of choices left at the given circle +// +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetDisciplineInfoObject +// Gets the disciplien info for the given class, telling what the chosen spells +// disicpline is, what type of maneuever it is, the different totals, and prerequisites. +// This is cached and is cleared when the window is refreshed/closed +// +// Argument: +// nClass:int class id +// +// Returns: +// JsonObject the object representation of the chosen spells discipline info +// +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF); + +// +// HasPreRequisitesForManeuver +// Does the player have the prerequisites for the given spell based off their chosen +// spell list +// +// Arguments: +// nClass:int the class id +// spellbookId:int the spellbook id +// oPC:object the player object with stored variables +// +// Returns: +// int:Boolean, TRUE if you have the prerequisites, FALSE otherwise +// +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// GetMaxInitiatorCircle +// gets the max circle/level a player can obtain with the given class +// +// Arguments: +// nClass:int the class id +// oPC:object the player +// +// Returns: +// int the highest circle the player can achieve with the class +// +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingManeuverChoices +// Gets remaining maneuever choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining maneuevers choices +// +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingStanceChoices +// Gets remaining stance choices for the player +// +// Arguments: +// nClass:int class id +// oPC:object the player +// +// Returns: +// int the remaining stance choices +// +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF); + +// +// IsRequiredForOtherManeuvers +// Checks the given prerequisite number and the chosen spells to see if removing it +// will cause it to fail the requirement for other maneuevers +// +// Arguments: +// nClass:int the class id +// prereq:int the chosen spells prerequisite number of maneuevers needed +// discipline:string the chosen spells discipline +// +// Returns: +// int:Boolean TRUE if it is required, FALSE otherwise +// +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF); + +// +// IsAllowedDiscipline +// checks to see if the given spell is a allowed discipline for a class +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:boolean TRUE if it is allowed, FALSE otherwise +// +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +// +// AddSpellDisciplineInfo +// Adds the maneuver's discipline info to the class's discpline object +// +// Arguments: +// sFile:string the class's spell 2da +// spellbookId:int the spellbook Id +// classDisc:JsonObject the class discipline object we are adding to +// +// Returns: +// json:Object the classDisc with the given spells information added +// +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc); + +// +// IsRequiredForToBPRCClass +// tells if a given maneuver is needed to satisfy a PRC's prerequsitie +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int:Boolean TRUE if the maneuver is required for a PRC, FALSE otherwise. +// +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetInvokerKnownListObject +// gets the invokers known invocations list in object format, needed to tell how many +// of each invocation level does a person know at a given level. This is cached on the +// player and not cleared since it never changes. +// +// Arguments: +// nClass:int class id +// +// Returns: +// json:Object the list of invocations known in json format +// +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF); + +// +// GetRemainingInvocationChoices +// Gets the remaining invocation choices left +// +// Arguments: +// nClass:int class id +// chosenCircle:int the chosen circle we are checking +// oPC:Object the player +// extra:int should we count the number of extra invocations we have left +// +// Returns: +// int the amount of choices left at the given circle +// +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE); + +// +// IsExtraChoiceInvocation +// tells if a given spell is a extra invocation choice +// +// Arguments: +// nClass:int class id +// spellbookId:int the spellbook id +// +// Returns: +// int;Boolean TRUE if it is a extra choice, FALSE otherwise +// +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +// +// GetRemainingTruenameChoices +// gets the remaining truename choices left at the given lexicon type +// +// Arguments: +// nClass:int class id +// nType:int the lexicon +// +// Returns: +// int the amount of truename choices left for the given lexicon +// +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF); + +// +// GetLexiconCircleKnownAtLevel +// gets the known circle level for a given lexicon +// +// Arguments: +// nLevel:int the level to check +// nType:int the lexicon we are checking +// +// Returns: +// int the highest circle we can achieve +// +int GetLexiconCircleKnownAtLevel(int nLevel, int nType); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF); + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Spont Casters / Base /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int IsLevelUpNUIOpen(object oPC=OBJECT_SELF) +{ + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + return TRUE; + } + + return FALSE; +} + +int IsClassAllowedToUseLevelUpNUI(int nClass) +{ + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + return TRUE; + + if (nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_WILDER + || nClass == CLASS_TYPE_WARMIND) + return TRUE; + + if (nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER) + return TRUE; + + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN) + return TRUE; + + if (nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH) + return TRUE; + + if (nClass == CLASS_TYPE_TRUENAMER) + return TRUE; + + if (nClass == CLASS_TYPE_ARCHIVIST) + return TRUE; + + return FALSE; +} + +int SpellIsWithinObject(int nClass, int spellbookId, int circleLevel, json spellList, object oPC=OBJECT_SELF) +{ + // check to see if the spell circle isn't empty + json currentList = JsonObjectGet(spellList, IntToString(circleLevel)); + if (currentList == JsonNull()) + return FALSE; + + int totalSpells = JsonGetLength(currentList); + + // then loop through the spell list and find the spell. + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpell = JsonGetInt(JsonArrayGet(currentList, i)); + if (currentSpell == spellbookId) + return TRUE; + } + + return FALSE; +} + +int AllSpellsAreChosen(int nClass, object oPC=OBJECT_SELF) +{ + // we need the max number of circles a class has. + json spellList = GetSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(spellList); + int totalCircles = JsonGetLength(spellCircles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and check if you have any remaining choices left + // if you do or you have a deficit then you need to remove or add something + // until you get 0 + int spellCircle = StringToInt(JsonGetString(JsonArrayGet(spellCircles, i))); + int remainingChoices = GetRemainingSpellChoices(nClass, spellCircle, oPC); + if (remainingChoices < 0 || remainingChoices > 0) + return FALSE; + } + + return TRUE; +} + +void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + if (GetIsInvocationClass(nClass)) + { + // get the remaining invocation choices left without extra feats + // if it is 0 then we are adding the chosen invocation to the extra lists + int totalInvocations = GetRemainingInvocationChoices(nClass, spellCircle, oPC, FALSE); + if (totalInvocations == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, INVOCATION_LIST_EXTRA_EPIC, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (GetIsPsionicClass(nClass)) + { + // if the power is a expanded knowledge than we immediatly add it to the + // extra list, otherwise check to make sure we have made all choices in our + // base list first before adding it to the extra list. + if (IsExpKnowledgePower(nClass, spellbookId) + || GetRemainingPowerChoices(nClass, spellCircle, oPC, FALSE) == 0) + { + string sFile = GetClassSpellbookFile(nClass); + if (GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)) + { + json expList = GetExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + } + else if (GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC)) + { + json expList = GetEpicExpandedChoicesList(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + expList = JsonObjectSet(expList, spellId, JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // add the power to the current power list. + json currPowerList = GetCurrentPowerList(oPC); + currPowerList = JsonArrayInsert(currPowerList, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerList); + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + newSpells = JsonArrayInsert(newSpells, JsonInt(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + } + + // base logic for spont casters, add the spell to the ChosenSpells JSON object + // by adding it to it's appropriate circle. + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + spellsAtCircle = JsonArrayInsert(spellsAtCircle, JsonInt(spellbookId)); + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we are not using bioware unlearning logic, then we need to limit the + // amount of spells we can replace. + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json unlearnList = GetChosenReplaceListObject(oPC); + // if the spell belongs to the unlearn list, then remove it to make room + // for a new spell. + if (JsonObjectGet(unlearnList, IntToString(spellbookId)) != JsonNull()) + { + unlearnList = JsonObjectDel(unlearnList, IntToString(spellbookId)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + } + } +} + +void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellsAtCircle = JsonObjectGet(chosenSpells, IntToString(spellCircle)); + if (spellsAtCircle == JsonNull()) + spellsAtCircle = JsonArray(); + + int totalSpells = JsonGetLength(spellsAtCircle); + + // find the spell at the circle in the chosen list and remove it. + int i; + for (i = 0; i < totalSpells; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(spellsAtCircle, i))) + { + spellsAtCircle = JsonArrayDel(spellsAtCircle, i); + break; + } + } + + chosenSpells = JsonObjectSet(chosenSpells, IntToString(spellCircle), spellsAtCircle); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, chosenSpells); + + // if we re not using bioware unlearn logic we need to limit how many spells + // can be replaced + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellListAtCircle = JsonObjectGet(knownSpells, IntToString(spellCircle)); + int totalSpells = JsonGetLength(spellListAtCircle); + + // with the list of known spells, check the selected circle and see if the + // current spell belongs in the already known spell list. + for (i = 0; i < totalSpells; i++) + { + int chosenSpell = JsonGetInt(JsonArrayGet(spellListAtCircle, i)); + if (chosenSpell == spellbookId) + { + // if it does we need to add the spell to the unlearn JSON object to track what spells + // are being replaced. + json unlearnList = GetChosenReplaceListObject(oPC); + unlearnList = JsonObjectSet(unlearnList, IntToString(spellbookId), JsonBool(TRUE)); + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, unlearnList); + break; + } + } + } + + if (GetIsPsionicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for psionics we need to check if the removed spell was a expanded knowledge choice + // or not. The id of the list is -1 or -2. + int i; + for (i == -1; i >= -2; i--) + { + json expList = (i == -1) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + //if the spell belongs in the expanded knowledge list, then we need + // to remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == POWER_LIST_EXP_KNOWLEDGE) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + + // then we need to remove the power from the selected powers list. + json currPowerChoices = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(currPowerChoices); + + for (i = 0; i < totalPowers; i++) + { + if (spellbookId == JsonGetInt(JsonArrayGet(currPowerChoices, i))) + { + currPowerChoices = JsonArrayDel(currPowerChoices, i); + break; + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, currPowerChoices); + } + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + + // for invocations we need to check if the spell was added to the extra + // invocations list, the list ids are the invalid class id, and -2 + int i; + for (i = 0; i <= 1; i++) + { + json expList = (i == 0) ? GetExpandedChoicesList(nClass, oPC) : + GetEpicExpandedChoicesList(nClass, oPC); + + // if the spell was found, remove it. + if (JsonObjectGet(expList, spellId) != JsonNull()) + { + expList = JsonObjectDel(expList, spellId); + if (i == 0) + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expList); + else + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expList); + } + } + } + if (nClass == CLASS_TYPE_ARCHIVIST) + { + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNew = JsonGetLength(newSpells); + + int i; + for (i = 0; i < totalNew; i++) + { + int newSpellbookId = JsonGetInt(JsonArrayGet(newSpells, i)); + if (newSpellbookId == spellbookId) + { + newSpells = JsonArrayDel(newSpells, i); + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, newSpells); + break; + } + } + } +} + +void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF) +{ + CloseNUILevelUpWindow(oPC); + // set the NUI to the given classId + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // we need to clear the cache if it was used before to avoid weird behaviors + ClearLevelUpNUICaches(currentClass, oPC); + // sometimes we are given a different classId instead of the base, we need to + // figure out what the true base class is (mostly true for RHD) + int chosenClass = GetTrueClassType(nClass, oPC); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass); + + ExecuteScript("prc_nui_lv_view", oPC); +} + +int GetTrueClassType(int nClass, object oPC=OBJECT_SELF) +{ + if (nClass == CLASS_TYPE_JADE_PHOENIX_MAGE + || nClass == CLASS_TYPE_MASTER_OF_NINE + || nClass == CLASS_TYPE_DEEPSTONE_SENTINEL + || nClass == CLASS_TYPE_BLOODCLAW_MASTER + || nClass == CLASS_TYPE_RUBY_VINDICATOR + || nClass == CLASS_TYPE_ETERNAL_BLADE + || nClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + int trueClass = GetPrimaryBladeMagicClass(oPC); + return trueClass; + } + + if ((nClass == CLASS_TYPE_SHAPECHANGER + && GetRacialType(oPC) == RACIAL_TYPE_ARANEA) + || (nClass == CLASS_TYPE_OUTSIDER + && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA) + || (nClass == CLASS_TYPE_ABERRATION + && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT)) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_FEY + && GetRacialType(oPC) == RACIAL_TYPE_GLOURA) + return CLASS_TYPE_BARD; + + return nClass; +} + +void CloseNUILevelUpWindow(object oPC=OBJECT_SELF) +{ + int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // if we are refreshing the NUI but not finished we need to clear some caching done + // to save computation time as they will need to be reprocessed. + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass)); + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20); + int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); + if (nPreviousToken != 0) + { + NuiDestroy(oPC, nPreviousToken); + } +} + +int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return FALSE; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return FALSE; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return FALSE; + } + + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return FALSE; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return TRUE; + return FALSE; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return FALSE; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return FALSE; + + // maneuvers and stances have their own seperate limits + string sFile = GetClassSpellbookFile(nClass); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return TRUE; + return FALSE; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return TRUE; + return FALSE; + } + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, GetCasterLevelByClass(nClass, oPC)); + if (circleLevel > maxLevel) + return FALSE; + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return TRUE; + + return FALSE; +} + +int ShouldAddSpellToSpellButtons(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + + string spellLevel = Get2DACache(sFile, "Level", spellbookId); + json chosenSpellsAtCircle = JsonObjectGet(chosenSpells, spellLevel); + + int chosenSpellCount = JsonGetLength(chosenSpellsAtCircle); + + // if the spell is in the chosen list, then don't add it to the available list + int i; + for (i = 0; i < chosenSpellCount; i++) + { + int chosenSpellId = JsonGetInt(JsonArrayGet(chosenSpellsAtCircle, i)); + if (chosenSpellId == spellbookId) + return FALSE; + } + + if (GetIsBladeMagicClass(nClass)) + return IsAllowedDiscipline(nClass, spellbookId, oPC); + + // if a psionic class we need to see if the power is a expanded knowledge + // choice and if we should show it or not + if (GetIsPsionicClass(nClass)) + return ShouldAddPower(nClass, spellbookId, oPC); + + // for these set of classes we need to only allow 'advanced learning' + // spells to be added + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return TRUE; + return FALSE; + } + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + if ((StringToInt(spellLevel) == 0) && (nLevel == 1)) + return FALSE; + int advancedLearning = StringToInt(Get2DACache(sFile, "AL", spellbookId)); + if (advancedLearning) + return FALSE; + } + + return TRUE; +} + +json GetChosenSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // if this isn't set yet then we the chosen currently is the known spells + if (retValue == JsonNull()) + { + retValue = GetKnownSpellListObject(nClass, oPC); + SetLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR, retValue); + } + + return retValue; +} + +json GetKnownSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int i; + for (i = 0; i < 10; i++) + { + string sSpellbook = GetSpellsKnown_Array(nClass, i); + + int nSize = persistant_array_get_size(oPC, sSpellbook); + + int j; + for (j = 0; j < nSize; j++) + { + int knownSpellbookID = persistant_array_get_int(oPC, sSpellbook, j); + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, IntToString(i)); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(knownSpellbookID)); + retValue = JsonObjectSet(retValue, IntToString(i), spellList); + } + } + } + else + { + // loop through all the spells in the class's 2da + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + // if you have the feat, you know the spell + if (featId && GetHasFeat(featId, oPC, TRUE)) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells have **** as their level, so make sure we have + // parsed it correctly + if (IntToString(nSpellLevel) == spellLevel) + { + // we store things in a JSON Object where the spell circle + // is the key to a JsonArray of spellbookIds. + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR, retValue); + return retValue; +} + +json GetSpellListObject(int nClass, object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass)); + if (retValue == JsonNull()) + retValue = JsonObject(); + else + return retValue; + + string sFile = GetClassSpellbookFile(nClass); + int totalSpells = Get2DARowCount(sFile); + + // loop through all the spells in the 2da and convert it to a JSON Object representation + int i; + for (i = 0; i < totalSpells; i++) + { + string spellLevel = Get2DACache(sFile, "Level", i); + int nSpellLevel = StringToInt(spellLevel); + // some spells in the list have **** as spell level. We need to ignore them + if (IntToString(nSpellLevel) == spellLevel) + { + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int reqFeat = StringToInt(Get2DACache(sFile, "ReqFeat", i)); + if (!reqFeat) + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + else + { + json spellList = JsonObjectGet(retValue, spellLevel); + if (spellList == JsonNull()) + spellList = JsonArray(); + spellList = JsonArrayInsert(spellList, JsonInt(i)); + retValue = JsonObjectSet(retValue, spellLevel, spellList); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR + IntToString(nClass), retValue); + return retValue; +} + +int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF) +{ + int chosenCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + int remainingChoices = 0; + + // we only want to cache on the current circle. + if (chosenCircle == circleLevel) + { + remainingChoices = GetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR); + // -20 is the chosen number to say there is no cache set since 0 is + // a valid option + if (remainingChoices != -20) + return remainingChoices; + } + + // logic for psionics + if (GetIsPsionicClass(nClass)) + remainingChoices = GetRemainingPowerChoices(nClass, circleLevel, oPC); + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + remainingChoices = (GetRemainingManeuverChoices(nClass, oPC) + + GetRemainingStanceChoices(nClass, oPC)); + + // logic for Invokers + if (GetIsInvocationClass(nClass)) + remainingChoices = GetRemainingInvocationChoices(nClass, circleLevel, oPC); + + // logic for mysteries + if (GetIsShadowMagicClass(nClass)) + { + int totalChosen = 0; + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + // loop through each circle and add its total spells together since + // we don't care about where you spend your spells, only the amount + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if (spellList != JsonNull()) + totalChosen += JsonGetLength(spellList); + } + + int maxKnown = GetMaxMysteryCount(oPC, nClass); + remainingChoices = (maxKnown - totalChosen); + } + + if (GetIsTruenamingClass(nClass)) + remainingChoices = GetRemainingTruenameChoices(nClass, -1, oPC); + + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC); + int spellsAvailable; + if (nLevel == 1) + spellsAvailable = (3 + GetAbilityModifier(ABILITY_INTELLIGENCE, oPC)); + else + spellsAvailable = 2; + + json newSpells = GetArchivistNewSpellsList(oPC); + int totalNewSpells = JsonGetLength(newSpells); + remainingChoices = (spellsAvailable - totalNewSpells); + } + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + int totalSpellsKnown = 0; + int casterLevel = GetCasterLevelByClass(nClass, oPC); + + // these specific classes only learn at specific rates + int advancedLearning = 0; + // beguiler learns every 4th level starting on 3 + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + // warmage is a bastard child that choses when it learns a spell whenever + // it decides it feels like it wants to + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) // 1 choice + advancedLearning++; + if (casterLevel >= 6) // 2 choice + advancedLearning++; + if (casterLevel >= 11) // 3 choice + advancedLearning++; + if (casterLevel >= 16) // 4 choice + advancedLearning++; + if (casterLevel >= 24) // 5 choice + advancedLearning++; + if (casterLevel >= 28) // 6 choice + advancedLearning++; + if (casterLevel >= 32) // 7 choice + advancedLearning++; + if (casterLevel >= 36) // 8 choice + advancedLearning++; + if (casterLevel >= 40) // 9 choice + advancedLearning++; + } + + if (advancedLearning) + { + int maxSpellLevel = GetMaxSpellLevelForCasterLevel(nClass, casterLevel); + // can't learn what you can't achieve + if (circleLevel > maxSpellLevel) + remainingChoices = 0; + else + { + int chosenSpellsAmount = 0; + + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + string sFile = GetClassSpellbookFile(nClass); + + int i; + for (i = 0; i <= totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json spellList = JsonObjectGet(chosenSpells, currentCircle); + if ((spellList != JsonNull())) + { + // loop through the spells of a given circle and count how + // many advanced learning spells you know + int numOfSpells = JsonGetLength(spellList); + int j; + for (j = 0; j < numOfSpells; j++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(spellList, j)); + int isAL = StringToInt(Get2DACache(sFile, "AL", nSpellbookID)); + if (isAL) + chosenSpellsAmount++; + } + } + } + + remainingChoices = (advancedLearning - chosenSpellsAmount); + } + } + else + { + // default logic for spont casters + totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC); + // Favoured Soul has more 0 choices than there are spells for some reason + if (nClass == CLASS_TYPE_FAVOURED_SOUL && circleLevel == 0 && totalSpellsKnown > 6) + totalSpellsKnown = 6; + + // logic for spont casters + json selectedCircle = JsonObjectGet(chosenSpells, IntToString(circleLevel)); + if (selectedCircle == JsonNull()) + return totalSpellsKnown; + + int selectedSpellCount = JsonGetLength(selectedCircle); + remainingChoices = (totalSpellsKnown - selectedSpellCount); + } + } + + if (chosenCircle == circleLevel) + SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices); + return remainingChoices; +} + +void FinishLevelUp(int nClass, object oPC=OBJECT_SELF) +{ + RemoveSpells(nClass, oPC); + LearnSpells(nClass, oPC); + if (nClass == CLASS_TYPE_ARCHIVIST) + { + int nLevel = GetLevelByClass(nClass, oPC); + SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel); + } + ClearLevelUpNUICaches(nClass, oPC); +} + +void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF) +{ + // clear the chosen spells you made + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + // clear the known spells you have + DeleteLocalJson(oPC, NUI_LEVEL_UP_KNOWN_SPELLS_VAR); + SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR, -1); + DeleteLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + // clear the psionics selected choices + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + // clear the expanded choices for psionics and invokers + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + // clear the PnP replace list + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + // for invocation and psionics we grab the list of known extra spells and cache it + // so we need to clear those caches + if (GetIsInvocationClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(INVOCATION_LIST_EXTRA_EPIC)); + } + if (GetIsPsionicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_0"); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EXP_KNOWLEDGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(POWER_LIST_EPIC_EXP_KNOWLEDGE)); + } + // for ToB we need to clear all the discipline info for determining PrC choice validity + if (GetIsBladeMagicClass(nClass)) + { + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_SWORDSAGE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_WARBLADE)); + DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(CLASS_TYPE_CRUSADER)); + } +} + +void RemoveSpells(int nClass, object oPC=OBJECT_SELF) +{ + // we don't remove on psionic classes and archivist + if (GetIsPsionicClass(nClass) || nClass == CLASS_TYPE_ARCHIVIST) + return; + + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(knownSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through all the known spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(knownSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the given circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not a chosen spell, then it was removed + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, chosenSpells, oPC)) + { + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = 0; + // check to see if its a extra invocation choice and set it's chosen list + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + json expList = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + } + RemoveSpellKnown(nClass, nSpellbookID, oPC, chosenList); + } + if (GetIsBladeMagicClass(nClass) || GetIsShadowMagicClass(nClass)) + RemoveSpellKnown(nClass, nSpellbookID, oPC); + + if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) + { + string sFile = GetClassSpellbookFile(nClass); + string sSpellBook = GetSpellsKnown_Array(nClass); + // remove the spell from the spellbook + array_extract_int(oPC, sSpellBook, nSpellbookID); + // wipe the spell from the player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + WipeSpellFromHide(ipFeatID, oPC); + } + } + } + } +} + +void LearnSpells(int nClass, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass)) + { + LearnPowers(nClass, oPC); + return; + } + + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json spellCircles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(spellCircles); + + // loop through chosen spells circles + int i; + for (i = 0; i < totalCircles; i++) + { + string sSpellLevel = JsonGetString(JsonArrayGet(spellCircles, i)); + int nSpellLevel = StringToInt(sSpellLevel); + + json chosenCircle = JsonObjectGet(chosenSpells, sSpellLevel); + int totalSpells = JsonGetLength(chosenCircle); + + // loop through the spell list at the circle + int y; + for (y = 0; y < totalSpells; y++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(chosenCircle, y)); + // if the spell is not in the known spell list then it was newly added + if (!SpellIsWithinObject(nClass, nSpellbookID, nSpellLevel, knownSpells, oPC)) + { + if (GetIsTruenamingClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + // find out what lexicon it belongs to and add it to that + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", nSpellbookID)); + AddUtteranceKnown(oPC, nClass, nSpellbookID, lexicon, TRUE, GetHitDice(oPC)); + } + + if (GetIsShadowMagicClass(nClass)) + AddMysteryKnown(oPC, nClass, nSpellbookID, TRUE, GetHitDice(oPC)); + + if (GetIsInvocationClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", nSpellbookID); + int chosenList = nClass; + json expList = GetExpandedChoicesList(nClass, oPC); + // if the invocation belongs to the extra or epic extra list + // then we need to provide those list ids instead. + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA; + expList = GetEpicExpandedChoicesList(nClass, oPC); + if (JsonObjectGet(expList, spellId) != JsonNull()) + chosenList = INVOCATION_LIST_EXTRA_EPIC; + AddInvocationKnown(oPC, chosenList, nSpellbookID, TRUE, GetHitDice(oPC)); + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int maneuverType = StringToInt(Get2DACache(sFile, "Type", nSpellbookID)); + // we save our moves either to stance or maneuever + if (maneuverType != MANEUVER_TYPE_STANCE) + maneuverType = MANEUVER_TYPE_MANEUVER; + + AddManeuverKnown(oPC, nClass, nSpellbookID, maneuverType, TRUE, GetHitDice(oPC)); + } + int nSpellbookType = GetSpellbookTypeForClass(nClass); + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS + || nClass == CLASS_TYPE_ARCHIVIST) + { + // these classes have their own syste, + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_WARMAGE) + { + int casterLevel = GetCasterLevelByClass(nClass, oPC); + // this is taken from prc_s_spellgain as it is coupled with the + // dynamic dialogue system + int advancedLearning = 0; + // beguilers learn every 4th level starting on 3rd + if (nClass == CLASS_TYPE_BEGUILER) + advancedLearning = ((casterLevel+1)/4); + // dread learns every 4th level + if (nClass == CLASS_TYPE_DREAD_NECROMANCER) + advancedLearning = (casterLevel/4); + if (nClass == CLASS_TYPE_WARMAGE) + { + if (casterLevel >= 3) + advancedLearning++; + } + + if (advancedLearning) + { + // incremenet the total advanced learning known + int nAdvLearn = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass)); + nAdvLearn++; + SetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass), nAdvLearn); + } + } + + // get location of persistant storage on the hide + string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel); + //object oToken = GetHideToken(oPC); + + // Create spells known persistant array if it is missing + int nSize = persistant_array_get_size(oPC, sSpellbook); + if (nSize < 0) + { + persistant_array_create(oPC, sSpellbook); + nSize = 0; + } + + // Mark the spell as known (e.g. add it to the end of oPCs spellbook) + persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID); + + if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS) + { + // add spell + string sFile = GetClassSpellbookFile(nClass); + string sArrayName = "NewSpellbookMem_" + IntToString(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID)); + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); + AddSpellUse(oPC, nSpellbookID, nClass, sFile, sArrayName, nSpellbookType, GetPCSkin(oPC), featId, ipFeatID); + } + } + } + } + } +} + +int EnableChosenButton(int nClass, int spellbookId, int circleLevel, object oPC=OBJECT_SELF) +{ + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE + || nClass == CLASS_TYPE_ARCHIVIST) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return FALSE; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return FALSE; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return FALSE; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return FALSE; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + return totalUnlearned < totalAllowed; + } + } + + } + + return TRUE; +} + +void ResetChoices(object oPC=OBJECT_SELF) +{ + // reset choices made so far + DeleteLocalJson(oPC, NUI_LEVEL_UP_CHOSEN_SPELLS_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + DeleteLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); +} + +void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int nList=0) +{ + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + string totalCountId; + + string sFile = GetClassSpellbookFile(nClass); + int chosenList = (nList != 0) ? nList : nClass; + int spellID = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + + // if statements are to change the location of the spellbook we are grabbing + if (GetIsShadowMagicClass(nClass)) + { + sBase = _MYSTERY_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _MYSTERY_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MYSTERY_LIST_GENERAL_ARRAY; + totalCountId = _MYSTERY_LIST_TOTAL_KNOWN; + } + + if (GetIsInvocationClass(nClass)) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + totalCountId = _INVOCATION_LIST_TOTAL_KNOWN; + } + + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType != MANEUVER_TYPE_STANCE) maneuverType = MANEUVER_TYPE_MANEUVER; + sBase = _MANEUVER_LIST_NAME_BASE + IntToString(chosenList) + IntToString(maneuverType); + levelArrayBaseId = _MANEUVER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _MANEUVER_LIST_GENERAL_ARRAY; + totalCountId = _MANEUVER_LIST_TOTAL_KNOWN; + } + + if (GetIsTruenamingClass(nClass)) + { + string lexicon = Get2DACache(sFile, "Lexicon", spellbookId); + sBase = _UTTERANCE_LIST_NAME_BASE + IntToString(chosenList) + lexicon; + levelArrayBaseId = _UTTERANCE_LIST_LEVEL_ARRAY; + generalArrayBaseId = _UTTERANCE_LIST_GENERAL_ARRAY; + totalCountId = _UTTERANCE_LIST_TOTAL_KNOWN; + } + + string sTestArray; + + int found = FALSE; + + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + // if we found the spell, then we remove it. + if (persistant_array_extract_int(oPC, sTestArray, spellID) >= 0) + { + found = TRUE; + break; + } + } + } + + if (!found) + { + // if not found we check the general list where spells aren't set to a level. + sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + //if we could not find the spell here, something went wrong + if (persistant_array_extract_int(oPC, sTestArray, spellID) < 0) + { + SendMessageToPC(oPC, "Could not find spellID " + IntToString(spellID) + " in the class's spellbook!"); + return; + } + } + } + + // decrement the amount of spells known. + SetPersistantLocalInt(oPC, sBase + totalCountId, + GetPersistantLocalInt(oPC, sBase + totalCountId) - 1 + ); + + // if ToB we need to decrement the specific discipline as well. + if (GetIsBladeMagicClass(nClass)) + { + int maneuverType = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (maneuverType == MANEUVER_TYPE_BOOST + || maneuverType == MANEUVER_TYPE_COUNTER + || maneuverType == MANEUVER_TYPE_STRIKE + || maneuverType == MANEUVER_TYPE_MANEUVER) + maneuverType = MANEUVER_TYPE_MANEUVER; + string sDisciplineArray = _MANEUVER_LIST_DISCIPLINE + IntToString(maneuverType) + "_" + Get2DACache(sFile, "Discipline", spellbookId); + SetPersistantLocalInt(oPC, sDisciplineArray, + GetPersistantLocalInt(oPC, sDisciplineArray) - 1); + } + + // remove spell from player + int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId)); + itemproperty ipFeat = PRCItemPropertyBonusFeat(ipFeatID); + object oSkin = GetPCSkin(oPC); + RemoveItemProperty(oSkin, ipFeat); + CheckAndRemoveFeat(oSkin, ipFeat); +} + +json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0) +{ + json spellIds = GetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList)); + if (spellIds == JsonNull()) + spellIds = JsonObject(); + else + return spellIds; + + string sBase; + string levelArrayBaseId; + string generalArrayBaseId; + // if we are given a listId then use that instead, used for extra choices and + // expanded knowledge + int chosenList = (nList != 0) ? nList : nClass; + // these if checks are for setting class specific ids + if (nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_WARLOCK) + { + sBase = _INVOCATION_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _INVOCATION_LIST_LEVEL_ARRAY; + generalArrayBaseId = _INVOCATION_LIST_GENERAL_ARRAY; + } + if (GetIsPsionicClass(nClass)) + { + sBase = _POWER_LIST_NAME_BASE + IntToString(chosenList); + levelArrayBaseId = _POWER_LIST_LEVEL_ARRAY; + generalArrayBaseId = _POWER_LIST_GENERAL_ARRAY; + } + + // go through the level list and translate the spellIds into a JSON Object + // structure for easier access. + int i; + for (i = 1; i <= GetHitDice(oPC); i++) + { + string sTestArray = sBase + levelArrayBaseId + IntToString(i); + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + } + + // go through the general list and translate the spellIds into a JSON Object + // structure for easier access. + string sTestArray = sBase + generalArrayBaseId; + if (persistant_array_exists(oPC, sTestArray)) + { + int nSize = persistant_array_get_size(oPC, sTestArray); + + int j; + for (j = 0; j < nSize; j++) + { + spellIds = JsonObjectSet(spellIds, IntToString(persistant_array_get_int(oPC, sTestArray, j)), JsonBool(TRUE)); + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_SPELLID_LIST_VAR + IntToString(nClass) + "_" + IntToString(nList), spellIds); + return spellIds; +} + +string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + // logic for psionics + if (GetIsPsionicClass(nClass)) + { + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (circleLevel > maxLevel) + return "You are unable to learn at this level currently."; + + // if its an expanded knowledge choice and we have already made all our + // exp knowledge choices then it needs to be disabled. + if (IsExpKnowledgePower(nClass, spellbookId)) + { + int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC) + + GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (!remainingExp) + return "You have no more expanded knowledge choices left."; + } + } + + if (GetIsShadowMagicClass(nClass)) + { + // mysteries are weird, the circles are sectioned by 1-3, 4-6, 7-9 + // if you do not have at least 2 choices from a circle you can't progress up + // so you can have access to circles 1,2,4,7,8 + int nType = 1; + if (circleLevel >= 4 && circleLevel <= 6) + nType = 2; + if (circleLevel >= 7 && circleLevel <= 9) + nType = 3; + int maxPossibleCircle = GetMaxMysteryLevelLearnable(oPC, nClass, nType); + if (circleLevel > maxPossibleCircle) + return "You are unable to learn at this level currently."; + } + + if (GetIsTruenamingClass(nClass)) + { + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // each lexicon learns at different rates + int maxCircle = GetLexiconCircleKnownAtLevel(GetLevelByClass(nClass, oPC), lexicon); + if (circleLevel > maxCircle) + return "You are unable to learn at this level currently."; + + if (GetRemainingTruenameChoices(nClass, lexicon, oPC)) + return ""; + return "You have made all your truenaming choices."; + } + + // logic for ToB + if (GetIsBladeMagicClass(nClass)) + { + if (circleLevel > GetMaxInitiatorCircle(nClass, oPC)) + return "You are unable to learn at this level currently."; + + // if you do not have the prerequisite amount of maneuevers to learn + // the maneuever, then you can't learn it. + if (!HasPreRequisitesForManeuver(nClass, spellbookId, oPC)) + return "You do not have the prerequisites for this maneuver."; + + // maneuvers and stances have their own seperate limits + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_BOOST + || type == MANEUVER_TYPE_COUNTER + || type == MANEUVER_TYPE_STRIKE + || type == MANEUVER_TYPE_MANEUVER) + { + int remainingMan = GetRemainingManeuverChoices(nClass, oPC); + if (remainingMan) + return ""; + return "You have made all your maneuver choices."; + } + if (type == MANEUVER_TYPE_STANCE) + { + int remainingStance = GetRemainingStanceChoices(nClass, oPC); + if (remainingStance) + return ""; + return "You have made all your stance choices."; + } + } + + // default logic + // determine remaining Spell/Power choices left for player, if there is any + // remaining, enable the buttons. + if (GetRemainingSpellChoices(nClass, circleLevel, oPC)) + return ""; + + return "You have made all your spell choices."; +} + +string ReasonForDisabledChosen(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int circleLevel = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + + + if (GetIsPsionicClass(nClass) + || GetIsShadowMagicClass(nClass) + || GetIsTruenamingClass(nClass) + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_WARMAGE) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + // if spell belongs to known spells, then disable, we don't allow + // replacing for these classes. + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + if (currentSpellbookId == spellbookId) + return "You cannot replace spells as this class."; + } + + } + + if (GetIsBladeMagicClass(nClass)) + { + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + // if the maneuver is required for others to exist, t hen disable it + if (IsRequiredForOtherManeuvers(nClass, prereqs, discipline, oPC)) + return "This maneuver is required for another maneuver."; + // if it is required for a PRC to exist, then disable it. + if (IsRequiredForToBPRCClass(nClass, spellbookId, oPC)) + return "This maneuver is reuquired for a PRC class."; + } + + if (GetIsInvocationClass(nClass)) + { + // dragon Shamans can't replace + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json invokKnown = GetSpellIDsKnown(nClass, oPC); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json chosenSpell = JsonObjectGet(invokKnown, spellId); + if (chosenSpell != JsonNull()) + return "You cannot replace invocations as this class."; + } + } + + // If we do not use the bioware unlearn system, we follow PnP + if (!GetPRCSwitch(PRC_BIO_UNLEARN)) + { + json knownSpells = GetKnownSpellListObject(nClass, oPC); + json currentCircle = JsonObjectGet(knownSpells, IntToString(circleLevel)); + int totalSpells = JsonGetLength(currentCircle); + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpellbookId = JsonGetInt(JsonArrayGet(currentCircle, i)); + // if the spell belongs to the known spell list, then we need to determine + if (currentSpellbookId == spellbookId) + { + json unlearnList = GetChosenReplaceListObject(oPC); + int totalUnlearned = JsonGetLength(unlearnList); + int totalAllowed = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR); + // we default to 1 if no max number of unlearns is set + if (!totalAllowed) + totalAllowed = 1; + // we cannot replace a spell if we have more than or equal to the + // amount of relearns allowed, therefore disable. + if (totalUnlearned < totalAllowed) + return ""; + return "You can only replace " + IntToString(totalAllowed) + " spells during level up."; + } + } + + } + + return ""; +} + +json GetExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA); + + SetLocalJson(oPC, NUI_LEVEL_UP_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int GetRemainingExpandedChoices(int nClass, int nList, object oPC=OBJECT_SELF) +{ + int remainingChoices = 0; + + json expandedList = (nList == INVOCATION_LIST_EXTRA || nList == POWER_LIST_EXP_KNOWLEDGE ) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + int expChoicesCount = JsonGetLength(JsonObjectKeys(expandedList)); + int maxExpChoices = (GetIsPsionicClass(nClass)) ? GetMaxPowerCount(oPC, nList) + : GetMaxInvocationCount(oPC, nList); + remainingChoices += (maxExpChoices - expChoicesCount); + + return remainingChoices; +} + +json GetEpicExpandedChoicesList(int nClass, object oPC=OBJECT_SELF) +{ + json expandedChoices = GetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR); + if (expandedChoices != JsonNull()) + return expandedChoices; + + if (GetIsPsionicClass(nClass)) + expandedChoices = GetSpellIDsKnown(nClass, oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + else + expandedChoices = GetSpellIDsKnown(nClass, oPC, INVOCATION_LIST_EXTRA_EPIC); + + SetLocalJson(oPC, NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR, expandedChoices); + return expandedChoices; +} + +int IsSpellInExpandedChoices(int nClass, int nList, int spellId, object oPC=OBJECT_SELF) +{ + json expList = (nList == POWER_LIST_EXP_KNOWLEDGE || nList == INVOCATION_LIST_EXTRA) ? GetExpandedChoicesList(nClass, oPC) + : GetEpicExpandedChoicesList(nClass, oPC); + + return (JsonObjectGet(expList, IntToString(spellId)) != JsonNull()); +} + +json GetChosenReplaceListObject(object oPC=OBJECT_SELF) +{ + json replaceList = GetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR); + if (replaceList == JsonNull()) + replaceList = JsonObject(); + else + return replaceList; + + SetLocalJson(oPC, NUI_LEVEL_UP_RELEARN_LIST_VAR, replaceList); + return replaceList; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Psionics /// +/// /// +//////////////////////////////////////////////////////////////////////////// + + +int IsExpKnowledgePower(int nClass, int spellbookId) +{ + string sFile = GetClassSpellbookFile(nClass); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + return isExp; +} + +json GetCurrentPowerList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_POWER_LIST_VAR, retValue); + return retValue; +} + +int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId)); + int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); + // if you don't have the prereqs for a power then don't add it. Specific for + // psions + if (!CheckPowerPrereqs(featId, oPC)) + return FALSE; + // if the power is a expanded knowledge power + if (isExp) + { + // and we have a expanded knowledge choice left to make then show + // the button + int addPower = FALSE; + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + int currentCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR); + + int choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC); + if (choicesLeft && (currentCircle <= (maxLevel-1))) + addPower = TRUE; + choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); + if (choicesLeft) + addPower = TRUE; + // otherwise don't show the button. + return addPower; + } + + return TRUE; +} + +void LearnPowers(int nClass, object oPC=OBJECT_SELF) +{ + // add normal powers + json powerList = GetCurrentPowerList(oPC); + int totalPowers = JsonGetLength(powerList); + int i; + for (i = 0; i < totalPowers; i++) + { + int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i)); + // get the expanded knowledge list we are adding to if any + int expKnow = GetExpKnowledgePowerListRequired(nClass, nSpellbookID, oPC); + AddPowerKnown(oPC, nClass, nSpellbookID, TRUE, GetManifesterLevel(oPC, nClass, TRUE), expKnow); + } +} + +int GetExpKnowledgePowerListRequired(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + + int i; + // expanded knowledge is -1, epic epxanded knowledge is -2 + for (i = -1; i >= -2; i--) + { + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + if (IsSpellInExpandedChoices(nClass, i, spellId, oPC)) + return i; + } + + return 0; +} + +int GetMaxPowerLevelForClass(int nClass, object oPC=OBJECT_SELF) +{ + string sFile = GetAMSKnownFileName(nClass); + int nLevel = GetManifesterLevel(oPC, nClass, TRUE); + // index is level - 1 since it starts at 0. + int maxLevel = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel-1)); + return maxLevel; +} + +int GetRemainingPowerChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + + int maxLevel = GetMaxPowerLevelForClass(nClass, oPC); + if (chosenCircle > maxLevel) + return 0; + + json choices = GetCurrentPowerList(oPC); + int totalChoices = JsonGetLength(choices); + int allowedChoices = GetMaxPowerCount(oPC, nClass); + int alreadyChosen = GetPowerCount(oPC, nClass); + string sFile = GetClassSpellbookFile(nClass); + + int i = 0; + for (i = 0; i < totalChoices; i++) + { + int spellbookId = JsonGetInt(JsonArrayGet(choices, i)); + int spellId = StringToInt(Get2DACache(sFile, "SpellID", spellbookId)); + //if the power is a expanded knowledge choice, don't count it + if (!IsSpellInExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, spellId, oPC) + && !IsSpellInExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, spellId, oPC)) + remaining++; + } + remaining = (allowedChoices - remaining - alreadyChosen); + + // if this is true we count expanded knowledge choices + if (extra) + { + if (GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1, oPC) && (chosenCircle <= (maxLevel-1))) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EXP_KNOWLEDGE); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1, oPC)) + { + int totalExp = GetMaxPowerCount(oPC, POWER_LIST_EPIC_EXP_KNOWLEDGE); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Initiators /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetDisciplineInfoObject(int nClass, object oPC=OBJECT_SELF) +{ + json disciplineInfo = GetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass)); + if (disciplineInfo == JsonNull()) + disciplineInfo = JsonObject(); + else + return disciplineInfo; + + int chosenClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); + string sFile = GetClassSpellbookFile(nClass); + + //if this is not the chosen class then we do not have a chosen spell list + // need to go through the class's 2da and check if you know the spell or not. + if (nClass != chosenClass) + { + int totalSpells = Get2DARowCount(sFile); + + int i; + for (i = 0; i < totalSpells; i++) + { + int featId = StringToInt(Get2DACache(sFile, "FeatID", i)); + if (featId && GetHasFeat(featId, oPC, TRUE)) + disciplineInfo = AddSpellDisciplineInfo(sFile, i, disciplineInfo); + } + } + else + { + json chosenMans = GetChosenSpellListObject(nClass, oPC); + + json circles = JsonObjectKeys(chosenMans); + int totalCircles = JsonGetLength(circles); + + int i; + for (i = 0; i < totalCircles; i++) + { + string currentCircle = JsonGetString(JsonArrayGet(circles, i)); + json currentList = JsonObjectGet(chosenMans, currentCircle); + int totalSpells = JsonGetLength(currentList); + + int y; + for (y = 0; y < totalSpells; y++) + { + int spellbookId = JsonGetInt(JsonArrayGet(currentList, y)); + disciplineInfo = AddSpellDisciplineInfo(sFile, spellbookId, disciplineInfo); + } + } + } + + SetLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(nClass), disciplineInfo); + return disciplineInfo; +} + +int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + int total = 0; + + // loop through each prereq level and add up it's totals (ie how many maneuevrs + // do we know with 0,1,2...,n prereqs. + int i; + for (i = 0; i <= prereq; i++) + { + + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + int currentDiscPrereq = JsonGetInt(JsonObjectGet(currDisc, discKey)); + total += currentDiscPrereq; + } + + // then from above the given prereq check if we have any prereq maneuevers taken + for (i = (prereq+1); i < NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT; i++) + { + json currDisc = JsonObjectGet(discInfo, discipline); + string discKey = ("Prereq_" + IntToString(i)); + json discPrereq = JsonObjectGet(currDisc, discKey); + if (discPrereq != JsonNull()) + { + // if we do take the total and subtract by one, if it is lower than + // than the prereq needed, it is required + if (total - 1 < i) + return TRUE; + + // otherwise add how many we have and move up and keep trying. + int currentDiscPrereq = JsonGetInt(discPrereq); + total += currentDiscPrereq; + } + } + + return FALSE; +} + +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + if (!prereqs) + return TRUE; + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json chosenDisc = JsonObjectGet(discInfo, discipline); + if (chosenDisc != JsonNull()) + { + int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + + JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE)))); + if (nManCount >= prereqs) + return TRUE; + } + + return FALSE; +} + +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF) +{ + int initiatorLevel = GetInitiatorLevel(oPC, nClass); + // initiators learn by ceiling(classLevel) + int highestCircle = (initiatorLevel + 1) / 2; + if (highestCircle > 9) + return 9; + return highestCircle; +} + +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jManAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_MANEUVER_TOTAL); + int nManAmount = 0; + if (jManAmount != JsonNull()) + nManAmount = JsonGetInt(jManAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER); + + return maxAmount - nManAmount; +} + +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jStanceAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_STANCE_TOTAL); + int nStanceAmount = 0; + if (jStanceAmount != JsonNull()) + nStanceAmount = JsonGetInt(jStanceAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE); + + return maxAmount - nStanceAmount; +} + +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic carried over from private function in discipline inc functions + // uses bitwise matching to tell if the discipline is allowed or not + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + int nOverride = GetPersistantLocalInt(oPC, "AllowedDisciplines"); + if(nOverride == 0) + { + switch(nClass) + { + case CLASS_TYPE_CRUSADER: nOverride = 322; break;//DISCIPLINE_DEVOTED_SPIRIT + DISCIPLINE_STONE_DRAGON + DISCIPLINE_WHITE_RAVEN + case CLASS_TYPE_SWORDSAGE: nOverride = 245; break;//DISCIPLINE_DESERT_WIND + DISCIPLINE_DIAMOND_MIND + DISCIPLINE_SETTING_SUN + DISCIPLINE_SHADOW_HAND + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + case CLASS_TYPE_WARBLADE: nOverride = 460; break;//DISCIPLINE_DIAMOND_MIND + DISCIPLINE_IRON_HEART + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + DISCIPLINE_WHITE_RAVEN + } + } + return nOverride & discipline; +} + +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + int currentClassPos = 1; + // loop through all the classes and look for a PRC + while (currentClassPos) + { + int currentClass = GetClassByPosition(currentClassPos, oPC); + // if we reached a non existant class, we reached the end. + if (currentClass != CLASS_TYPE_INVALID) + { + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + // check if the class is a ToB PRC Class and if the current spell's + // discipline is used for it. + int isUsed = FALSE; + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL + && (discipline == DISCIPLINE_STONE_DRAGON)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER + && (discipline == DISCIPLINE_TIGER_CLAW)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR + && (discipline == DISCIPLINE_DEVOTED_SPIRIT)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_ETERNAL_BLADE + && (discipline == DISCIPLINE_DEVOTED_SPIRIT + || discipline == DISCIPLINE_DIAMOND_MIND)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA + && (discipline == DISCIPLINE_SETTING_SUN + || discipline == DISCIPLINE_SHADOW_HAND)) + isUsed = TRUE; + + // if any of the above was true than we need to check if this spell + // is required for a PRC + if (isUsed) + { + // get the discipline info for all BladeMagic classes if we have them. + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json classDisc2Info = JsonObject(); + json classDisc3Info = JsonObject(); + if (nClass == CLASS_TYPE_SWORDSAGE) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + } + if (nClass == CLASS_TYPE_CRUSADER) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + if (nClass == CLASS_TYPE_WARBLADE) + { + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + + // Time to begin checking the PRCs + // this should follow the same logic as here + // https://gitea.raptio.us/Jaysyn/PRC8/src/commit/797442d3da7c9c8e1fcf585b97e2ff1cbe56045b/nwn/nwnprc/trunk/scripts/prc_prereq.nss#L991 + + // Check Deepstone Sentinel + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL) + { + // we need to look for 2 Stone Dragon Maneuvers and 1 Stone Dragon + // Stance. So add up the other MagicBlade classes and see if it is satisfied. + int stoneDMan, stoneDStance = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + // if it still isn't satisfied than the current class is required + // for it to exist. Check to see if it is safe to remove the maneuever + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + //if the current maneuver is a stance, check to see if it is safe to remove + if (type == MANEUVER_TYPE_STANCE) + { + if (stoneDStance - 1 >= 1) + return FALSE; + } + else + { + // if it is not a stance we can just check the maneuevers in general + if (stoneDMan - 1 >= 2) + return FALSE; + } + + // this maneuver is required and should not be removed. + return TRUE; + } + } + + // Check Bloodclaw Master + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER) + { + // bloodclaw needs 3 Tiger Claw maneuevers + int tigerCMan = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan-1 >= 3) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR) + { + // Ruby Vindicator needs 1 stance and 1 maneuever from Devoted Spirit + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if (stance - 1 >= 1) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 1) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + { + // Jade Phoenix needs 1 stance and 2 maneuvers of any type + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if ((stance - 1 >= 1) && (maneuver -1 >= 2)) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + { + // master of nine needs 1 maneuever from 6 different disciplines + + int totalDiscCount = 0; + int currentClassAndDiscUsed = 0; + int i; + // loop through each possible discipline + for (i = 0; i <= 256; i++) + { + int found = 0; + // only disciplines that exist are stored, and only those + // that are used are stored, so we can loop through and + // find what disciplines we do or don't know. + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + + if (!found) + { + json currentDisc = JsonObjectGet(classDisc3Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + } + + if (!found) + { + json currentDisc = JsonObjectGet(discInfo, IntToString(i)); + if (currentDisc != JsonNull()) + { + if (i == discipline) + currentClassAndDiscUsed = 1; + found = 1; + } + } + + totalDiscCount += found; + } + // if we have more maneuevers than 6, it is not required + if (totalDiscCount > 6) + return FALSE; + // however if we have 6 and this discipline was grabbed we need to make sure it is safe to remove + if (currentClassAndDiscUsed) + { + // if we were to remove this discipline and it is 5 or less total disciplines we have now + // it is important + if (totalDiscCount - 1 >= 6) + return FALSE; + json currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + int stance = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int maneuver = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // if we were to remove this discipline and are left with no more than + // this was important and it can't be removed + if ((stance + maneuver - 1) >= 1) + return FALSE; + return TRUE; + } + return FALSE; + } + + if (currentClass == CLASS_TYPE_ETERNAL_BLADE) + { + //Eternal blade 2 Devoted Spirits OR 2 Diamond Mind + int nTotal = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if ((nTotal - 1) >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + // Shadow Sun Ninja needs 1 lvl2 Setting Sun OR Shadow Hand maneuever + // 1 Setting Sun maneuver AND 1 Shadow Hand maneuver + int nLvl2 = 0; + int shadowHTotal; + int settingSTotal; + + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + if (level == 2) + nLvl2 -= 1; + if (discipline == DISCIPLINE_SHADOW_HAND) + shadowHTotal -= 1; + else + settingSTotal -= 1; + + return !(nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)); + } + } + + currentClassPos += 1; + } + else + currentClassPos = 0; + } + + return FALSE; +} + +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc) +{ + json classDiscCopy = classDisc; + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + int prereq = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + + json jDisc = JsonObjectGet(classDisc, IntToString(discipline)); + if (jDisc == JsonNull()) + jDisc = JsonObject(); + + string levelKey = "Level" + IntToString(level) + "_" + IntToString(type); + int nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(type))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(type), JsonInt(nTypeTotal)); + + if (type != MANEUVER_TYPE_MANEUVER + && type != MANEUVER_TYPE_STANCE) + { + levelKey = "Level" + IntToString(level) + "_" + IntToString(MANEUVER_TYPE_MANEUVER); + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER), JsonInt(nTypeTotal)); + } + + string prereqKey = "Prereq_" + IntToString(prereq); + int nPrereqTotal = (JsonGetInt(JsonObjectGet(jDisc, prereqKey)) + 1); + jDisc = JsonObjectSet(jDisc, prereqKey, JsonInt(nPrereqTotal)); + + if (type == MANEUVER_TYPE_STANCE) + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_STANCE_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_STANCE_TOTAL, JsonInt(nTypeTotal)); + } + else + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_MANEUVER_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_MANEUVER_TOTAL, JsonInt(nTypeTotal)); + } + + return JsonObjectSet(classDiscCopy, IntToString(discipline), jDisc); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF) +{ + json knownObject = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass)); + if (knownObject == JsonNull()) + knownObject = JsonObject(); + else + return knownObject; + + string sFile = GetAMSKnownFileName(nClass); + int totalRows = Get2DARowCount(sFile); + int maxInvocLevel = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", totalRows-1)); + json previousInvocList = JsonObject(); + + int i; + for (i = 1; i <= maxInvocLevel; i++) + { + previousInvocList = JsonObjectSet(previousInvocList, IntToString(i), JsonInt(0)); + } + + for (i = 0; i < totalRows; i++) + { + int maxInvocation = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", i)); + int invocationKnown = StringToInt(Get2DACache(sFile, "InvocationKnown", i)); + json invocList = previousInvocList; + + int previousInvocTotal = 0; + if (i > 0) + previousInvocTotal = StringToInt(Get2DACache(sFile, "InvocationKnown", i-1)); + int previousInvocAmount = JsonGetInt(JsonObjectGet(previousInvocList, IntToString(maxInvocation))); + int currentInvocationAmount = (invocationKnown - previousInvocTotal + previousInvocAmount); + + invocList = JsonObjectSet(invocList, IntToString(maxInvocation), JsonInt(currentInvocationAmount)); + knownObject = JsonObjectSet(knownObject, IntToString(i+1), invocList); + previousInvocList = invocList; + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass), knownObject); + return knownObject; +} + +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + int nLevel = GetInvokerLevel(oPC, nClass); + + json knownObject = GetInvokerKnownListObject(nClass, oPC); + json chosenInv = GetChosenSpellListObject(nClass, oPC); + json currentLevelKnown = JsonObjectGet(knownObject, IntToString(nLevel)); + + int totalCircles = JsonGetLength(JsonObjectKeys(currentLevelKnown)); + + // logic goes we are given a set amount of invocations at each circle. We can + // take from a circle above us, but not below us. So we need to make sure + // we have a legal amount of choices + int i; + for (i = 1; i <= totalCircles; i++) + { + int currentChosen = 0; + json chosenSpells = JsonObjectGet(chosenInv, IntToString(i)); + if (chosenSpells != JsonNull()) + { + int totalChosen = JsonGetLength(chosenSpells); + int j; + for (j = 0; j < totalChosen; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(chosenSpells, j)); + // only count non extra invocation choices + if (!IsExtraChoiceInvocation(nClass, spellbookId, oPC)) + currentChosen += 1; + } + } + + int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i))); + + remaining = (allowedAtCircle - currentChosen + remaining); + // if the circle is below the chosen circle and we have a positive remaining, + // we set it to 0 because we cannot use lower circle spells on higher circle. + // however if thge value is negative then we carry it over because we + // have a deficit and need to account for it by using the spells of the + // next circle. + if (i < chosenCircle && remaining > 0) + remaining = 0; + } + + + // count extra and epic invocation choices + if (extra) + { + string sFile = GetAMSKnownFileName(nClass); + int maxCircle = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", nLevel-1)); + + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC) && (chosenCircle <= (maxCircle-1))) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA_EPIC); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json extraChoices = GetExpandedChoicesList(nClass, oPC); + json chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + extraChoices = GetEpicExpandedChoicesList(nClass, oPC); + chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int remainingChoices = 0; + + int i; + for (i = 0; i < totalCircles; i++) + { + json spellList = JsonObjectGet(chosenSpells, JsonGetString(JsonArrayGet(circles, i))); + if (spellList != JsonNull()) + { + int totalChoices = JsonGetLength(spellList); + + int j; + for (j = 0; j < totalChoices; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(spellList, j)); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // -1 means count all lexicons + if (nType == -1 || lexicon == nType) + remainingChoices += 1; + } + } + } + + int maxChoices; + // if -1 we count all lexicons to get total remaining + if (nType == -1) + maxChoices = (GetMaxUtteranceCount(oPC, nClass, LEXICON_CRAFTED_TOOL) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_EVOLVING_MIND) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_PERFECTED_MAP)); + else + maxChoices = GetMaxUtteranceCount(oPC, nClass, nType); + return (maxChoices - remainingChoices); +} + +int GetLexiconCircleKnownAtLevel(int nLevel, int nType) +{ + + string sFile = "cls_true_maxlvl"; + + string columnName; + if (nType == LEXICON_EVOLVING_MIND) + columnName = "EvolvingMind"; + else if (nType == LEXICON_CRAFTED_TOOL) + columnName = "CraftedTool"; + else + columnName = "PerfectedMap"; + + return StringToInt(Get2DACache(sFile, columnName, nLevel-1)); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue); + return retValue; +} + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_nui_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 99% rename from src/include/prc_nui_scd_inc.nss rename to src/include/prc_nui_sbd_inc.nss index 5f14b7e..4f84658 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 diff --git a/src/include/prc_spell_const.nss b/src/include/prc_spell_const.nss index bb8b1cd..02a3a2f 100644 --- a/src/include/prc_spell_const.nss +++ b/src/include/prc_spell_const.nss @@ -22,6 +22,9 @@ const int SPELL_BCM_RENDING_CLAWS = 17997; //:: Complete Warrior const int SPELL_RANGED_DISARM = 3493; +//:: Tome of Battle +const int SPELL_TOB_SNAP_KICK = 3794; + //marshal const int SPELL_MINAUR_DEMFORT = 3500; const int SPELL_MINAUR_FORCEWILL = 3501; @@ -1289,6 +1292,69 @@ const int SPELL_SUMMON_CREATURE_IX_WATER = 3200; //:: Player's Handbook Spells const int SPELL_SPIRITUAL_WEAPON = 17249; +const int SPELL_SUMMON_NATURES_ALLY_1 = 17000; +const int SPELL_SUMMON_NATURES_ALLY_1_DIREBADGER = 17001; +const int SPELL_SUMMON_NATURES_ALLY_1_DIRERAT = 17002; +const int SPELL_SUMMON_NATURES_ALLY_1_DOG = 17003; +const int SPELL_SUMMON_NATURES_ALLY_1_HAWK = 17004; +const int SPELL_SUMMON_NATURES_ALLY_1_TINY_VIPER = 17005; + +const int SPELL_SUMMON_NATURES_ALLY_2 = 17010; +const int SPELL_SUMMON_NATURES_ALLY_2_DIREBOAR = 17011; +const int SPELL_SUMMON_NATURES_ALLY_2_COOSHEE = 17012; +const int SPELL_SUMMON_NATURES_ALLY_2_WOLF = 17013; +const int SPELL_SUMMON_NATURES_ALLY_2_SMALL_VIPER = 17014; +const int SPELL_SUMMON_NATURES_ALLY_2_BLACKBEAR = 17015; + +const int SPELL_SUMMON_NATURES_ALLY_3 = 17020; +const int SPELL_SUMMON_NATURES_ALLY_3_BROWNBEAR = 17021; +const int SPELL_SUMMON_NATURES_ALLY_3_DIREWOLK = 17022; +const int SPELL_SUMMON_NATURES_ALLY_3_LARGE_VIPER = 17023; +const int SPELL_SUMMON_NATURES_ALLY_3_LEOPARD = 17024; +const int SPELL_SUMMON_NATURES_ALLY_3_SATYR = 17025; + +const int SPELL_SUMMON_NATURES_ALLY_4 = 17030; +const int SPELL_SUMMON_NATURES_ALLY_4_LION = 17031; +const int SPELL_SUMMON_NATURES_ALLY_4_POLAR_BEAR = 17032; +const int SPELL_SUMMON_NATURES_ALLY_4_DIRE_SPIDER = 17033; +const int SPELL_SUMMON_NATURES_ALLY_4_HUGE_VIPER = 17034; +const int SPELL_SUMMON_NATURES_ALLY_4_WEREBOAR = 17035; + +const int SPELL_SUMMON_NATURES_ALLY_5 = 17040; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_AIR = 17041; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_EARTH = 17042; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_FIRE = 17043; +const int SPELL_SUMMON_NATURES_ALLY_5_MED_WATER = 17044; +const int SPELL_SUMMON_NATURES_ALLY_5_DIRE_BEAR = 17045; + +const int SPELL_SUMMON_NATURES_ALLY_6 = 17050; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_AIR = 17051; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_EARTH = 17052; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_FIRE = 17053; +const int SPELL_SUMMON_NATURES_ALLY_6_LG_WATER = 17054; +const int SPELL_SUMMON_NATURES_ALLY_6_DIRETIGER = 17055; + +const int SPELL_SUMMON_NATURES_ALLY_7 = 17060; +const int SPELL_SUMMON_NATURES_ALLY_7_BULETTE = 17061; +const int SPELL_SUMMON_NATURES_ALLY_7_INVSTALKER = 17062; +const int SPELL_SUMMON_NATURES_ALLY_7_PIXIE = 17063; +const int SPELL_SUMMON_NATURES_ALLY_7_GORGON = 17064; +const int SPELL_SUMMON_NATURES_ALLY_7_MANTICORE = 17065; + +const int SPELL_SUMMON_NATURES_ALLY_8 = 17070; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_AIR = 17071; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_EARTH = 17072; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_FIRE = 17073; +const int SPELL_SUMMON_NATURES_ALLY_8_GR_WATER = 17074; +const int SPELL_SUMMON_NATURES_ALLY_8_NYMPH = 17075; + +const int SPELL_SUMMON_NATURES_ALLY_9 = 17080; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_AIR = 17081; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_EARTH = 17082; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_FIRE = 17083; +const int SPELL_SUMMON_NATURES_ALLY_9_ELD_WATER = 17084; +const int SPELL_SUMMON_NATURES_ALLY_9_ARANEA = 17085; + //:: Player's Handbook II Spells const int SPELL_CHASING_PERFECTION = 2479; @@ -1297,12 +1363,34 @@ const int SPELL_SPIRIT_WORM = 17248; const int SPELL_FORCE_MISSILES = 2480; //:: Masters of the Wild Spells +const int SPELL_FORESTFOLD = 17090; +const int SPELL_CREEPING_COLD = 17091; +const int SPELL_GREATER_CREEPING_COLD = 17092; +const int SPELL_CONTROL_PLANTS = 17237; +const int SPELL_ADRENALINE_SURGE = 17238; +const int SPELL_INVULNERABILITY_TO_ELEMENTS = 17239; +const int SPELL_REGEN_RING = 17241; +const int SPELL_REGEN_CIRCLE = 17242; const int SPELL_REGEN_LIGHT_WOUNDS = 17243; const int SPELL_REGEN_MODERATE_WOUNDS = 17244; const int SPELL_REGEN_SERIOUS_WOUNDS = 17245; const int SPELL_REGEN_CRITICAL_WOUNDS = 17246; const int SPELL_SPEED_WIND = 17247; -const int SPELL_TORTISE_SHELL = 17250; +const int SPELL_TORTISE_SHELL = 17250; + +//:: Book of Exalted Deeds Spells +const int SPELL_LEONALS_ROAR = 17240; + +//:: Master of the Wild Feats +const int SPELL_VL_WILD_SHAPE_TREANT = 17989; +const int SPELL_VL_ANIMATE_TREE = 17990; +const int SPELL_PLANT_DEFIANCE = 17991; +const int SPELL_PLANT_CONTROL = 17992; + +//:: Book of Exalted Deeds Feats +const int SPELL_FOT_LEONALS_ROAR = 17993; +const int SPELL_FOT_LIONS_SWIFTNESS = 17994; +const int SPELL_FAVORED_OF_THE_COMPANIONS = 17995; //x const int SPELL_TENSERS_FLOATING_DISK = 3849; diff --git a/src/include/prc_spellf_inc.nss b/src/include/prc_spellf_inc.nss index 753680f..1b6042f 100644 --- a/src/include/prc_spellf_inc.nss +++ b/src/include/prc_spellf_inc.nss @@ -299,6 +299,7 @@ int SpellfireDrainItem(object oPC, object oItem, int bCharged = TRUE, int bSingl { if((nBase == BASE_ITEM_POTIONS) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_SCROLL) || (nBase == BASE_ITEM_SPELLSCROLL) || (nBase == BASE_ITEM_BLANK_POTION) || @@ -382,6 +383,7 @@ void SpellfireDrain(object oPC, object oTarget, int bCharged = TRUE, int bExempt if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_DRAIN_SCROLL_POTION) && ((nBase == BASE_ITEM_POTIONS) || (nBase == BASE_ITEM_SCROLL) || + (nBase == BASE_ITEM_INFUSED_HERB) || (nBase == BASE_ITEM_BLANK_POTION) || (nBase == BASE_ITEM_BLANK_SCROLL) ) @@ -525,3 +527,4 @@ void SpellfireCrown(object oPC) } } +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_template_con.nss b/src/include/prc_template_con.nss index fc15544..2955524 100644 --- a/src/include/prc_template_con.nss +++ b/src/include/prc_template_con.nss @@ -18,6 +18,7 @@ const int TEMPLATE_CURST = 26; const int TEMPLATE_GRAVETOUCHED_GHOUL = 29; const int TEMPLATE_CRYPTSPAWN = 30; const int TEMPLATE_ARCHLICH = 99; +const int TEMPLATE_BAELNORN = 100; const int TEMPLATE_LICH = 101; const int TEMPLATE_DEMILICH = 102; const int TEMPLATE_NECROPOLITAN = 105; diff --git a/src/include/prc_x2_craft.nss b/src/include/prc_x2_craft.nss index 5834f63..ac1d795 100644 --- a/src/include/prc_x2_craft.nss +++ b/src/include/prc_x2_craft.nss @@ -13,7 +13,7 @@ //:: Created On: 2003-05-09 //:: Last Updated On: 2003-10-14 //::////////////////////////////////////////////// - +#include "prc_x2_itemprop" struct craft_struct { @@ -44,22 +44,24 @@ const string X2_CI_CRAFTSKILL_CONV ="x2_p_craftskills"; /* moved to be code switches const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions -const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier +const int PRC_X2_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier // Scribe Scroll related constants -const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier +const int PRC_X2_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier // Craft Wand related constants -const int X2_CI_CRAFTWAND_MAXLEVEL = 4; -const int X2_CI_CRAFTWAND_COSTMODIFIER = 750; +const int PRC_X2_CRAFTWAND_MAXLEVEL = 4; +const int PRC_X2_CRAFTWAND_COSTMODIFIER = 750; */ -const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation -const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; -const int X2_CI_CRAFTWAND_FEAT_ID = 946; -const int X2_CI_CRAFTROD_FEAT_ID = 2927; -const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; -const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; -const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation +const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; +const int X2_CI_CRAFTWAND_FEAT_ID = 946; +const int X2_CI_CRAFTROD_FEAT_ID = 2927; +const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490; +const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928; +const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491; +const int X2_CI_CREATEINFUSION_FEAT_ID = 25960; + const string X2_CI_BREWPOTION_NEWITEM_RESREF = "x2_it_pcpotion"; // ResRef for new potion item const string X2_CI_SCRIBESCROLL_NEWITEM_RESREF = "x2_it_pcscroll"; // ResRef for new scroll item const string X2_CI_CRAFTWAND_NEWITEM_RESREF = "x2_it_pcwand"; @@ -185,6 +187,17 @@ int CheckAlternativeCrafting(object oPC, int nSpell, struct craft_cost_struct co // Returns the maximum of caster level used and other effective levels from emulating spells int GetAlternativeCasterLevel(object oPC, int nLevel); +// ----------------------------------------------------------------------------- +// Create and Return an herbal infusion with an item property +// matching nSpellID. +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID); + +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0); + ////////////////////////////////////////////////// /* Include section */ ////////////////////////////////////////////////// @@ -194,6 +207,7 @@ int GetAlternativeCasterLevel(object oPC, int nLevel); #include "prc_inc_newip" #include "prc_inc_spells" #include "prc_add_spell_dc" +#include "inc_infusion" ////////////////////////////////////////////////// /* Function definitions */ @@ -261,7 +275,8 @@ int CIGetIsCraftFeatBaseItem(object oItem) nBt == BASE_ITEM_BLANK_SCROLL || nBt == BASE_ITEM_BLANK_WAND || nBt == BASE_ITEM_CRAFTED_ROD || - nBt == BASE_ITEM_CRAFTED_STAFF) + nBt == BASE_ITEM_CRAFTED_STAFF || + nBt == BASE_ITEM_MUNDANE_HERB) return TRUE; else return FALSE; @@ -453,11 +468,158 @@ object CICraftCraftWand(object oCreator, int nSpellID ) // ----------------------------------------------------------------------------- // Georg, 2003-06-12 -// Create and Return a magic wand with an item property -// matching nSpellID. Charges are set to d20 + casterlevel -// capped at 50 max +// Create and Return a magic scroll with an item property +// matching nSpellID. // ----------------------------------------------------------------------------- object CICraftScribeScroll(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("CICraftScribeScroll: Enter (nSpellID=" + IntToString(nSpellID) + ")"); + + // Keep original and compute one-step master (if subradial) + int nSpellOriginal = nSpellID; + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICraftScribeScroll: subradial detected original=" + IntToString(nSpellOriginal) + " master=" + IntToString(nSpellMaster)); + } + + // Prefer iprp mapping for the original, fallback to master + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If neither original nor master has an iprp row, we can still try templates, + // but most templates expect a matching iprp. Bail out now if nothing found. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICraftScribeScroll: no iprp_spells entry for original/master -> aborting"); + FloatingTextStringOnCreature("This spell cannot be scribed (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Material component check (based on resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Resolve class and scroll template + int nClass = PRCGetLastSpellCastClass(); + string sClass = ""; + switch (nClass) + { + case CLASS_TYPE_WIZARD: + case CLASS_TYPE_SORCERER: sClass = "Wiz_Sorc"; break; + case CLASS_TYPE_CLERIC: + case CLASS_TYPE_UR_PRIEST: sClass = "Cleric"; break; + case CLASS_TYPE_PALADIN: sClass = "Paladin"; break; + case CLASS_TYPE_DRUID: + case CLASS_TYPE_BLIGHTER: sClass = "Druid"; break; + case CLASS_TYPE_RANGER: sClass = "Ranger"; break; + case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: sClass = "Assassin"; break; + } + + object oTarget = OBJECT_INVALID; + string sResRef = ""; + + // Try to find a class-specific scroll template. + if (sClass != "") + { + // Try original first (so if you made a subradial-specific template it will be used) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellOriginal); + if (sResRef == "") + { + // fallback to the spell that matched an iprp row (master or original) + sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellUsedForIP); + } + if (sResRef != "") + { + oTarget = CreateItemOnObject(sResRef, oCreator); + if (DEBUG) DoDebug("CICraftScribeScroll: created template " + sResRef + " for class " + sClass); + // Ensure template uses the correct cast-spell property: replace the template's cast-spell IP with ours + if (oTarget != OBJECT_INVALID) + { + itemproperty ipIter = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipIter)) + { + if (GetItemPropertyType(ipIter) == ITEM_PROPERTY_CAST_SPELL) + { + RemoveItemProperty(oTarget, ipIter); + break; + } + ipIter = GetNextItemProperty(oTarget); + } + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + } + } + + // If no template or sClass was empty, create generic scroll and add itemprop. + if (oTarget == OBJECT_INVALID) + { + sResRef = "craft_scroll"; + oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("CICraftScribeScroll: failed to create craft_scroll template."); + return OBJECT_INVALID; + } + // Remove existing default IP and add correct one + itemproperty ipFirst = GetFirstItemProperty(oTarget); + if (GetIsItemPropertyValid(ipFirst)) + RemoveItemProperty(oTarget, ipFirst); + + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + } + + // Add PRC metadata (use the same spell that matched the iprp row so metadata and IP line up) + if (GetPRCSwitch(PRC_SCRIBE_SCROLL_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("prc_x2_craft::CICraftScribeScroll failed - Resref: " + sResRef + " Class: " + sClass + "(" + IntToString(nClass) + ") " + " SpellID " + IntToString(nSpellID)); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICraftScribeScroll: Success - created scroll " + sResRef + " for spell " + IntToString(nSpellUsedForIP)); + return oTarget; +} + + +/* object CICraftScribeScroll(object oCreator, int nSpellID) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; @@ -491,6 +653,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) break; case CLASS_TYPE_CLERIC: case CLASS_TYPE_UR_PRIEST: + case CLASS_TYPE_OCULAR: sClass = "Cleric"; break; case CLASS_TYPE_PALADIN: @@ -506,6 +669,9 @@ object CICraftScribeScroll(object oCreator, int nSpellID) case CLASS_TYPE_BARD: sClass = "Bard"; break; + case CLASS_TYPE_ASSASSIN: + sClass = "Assassin"; + break; } string sResRef; if (sClass != "") @@ -542,7 +708,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID) } return oTarget; } - + */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to brew a potion // ----------------------------------------------------------------------------- @@ -593,7 +759,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for brew potions // ------------------------------------------------------------------------- - int nPotionMaxLevel = GetPRCSwitch(X2_CI_BREWPOTION_MAXLEVEL); + int nPotionMaxLevel = GetPRCSwitch(PRC_X2_BREWPOTION_MAXLEVEL); if(nPotionMaxLevel == 0) nPotionMaxLevel = 3; @@ -624,7 +790,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostModifier = GetPRCSwitch(X2_CI_BREWPOTION_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_BREWPOTION_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 50; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_BREW_POTION_CASTER_LEVEL); @@ -728,7 +894,7 @@ int CICraftCheckScribeScroll(object oSpellTarget, object oCaster, int nID = 0) // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nLevel = CIGetSpellInnateLevel(nID,TRUE); - int nCostModifier = GetPRCSwitch(X2_CI_SCRIBESCROLL_COSTMODIFIER); + int nCostModifier = GetPRCSwitch(PRC_X2_SCRIBESCROLL_COSTMODIFIER); if(nCostModifier == 0) nCostModifier = 25; int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_SCRIBE_SCROLL_CASTER_LEVEL); @@ -884,7 +1050,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // check if spell is below maxlevel for craft want // ------------------------------------------------------------------------- - int nMaxLevel = GetPRCSwitch(X2_CI_CRAFTWAND_MAXLEVEL); + int nMaxLevel = GetPRCSwitch(PRC_X2_CRAFTWAND_MAXLEVEL); if(nMaxLevel == 0) nMaxLevel = 4; if (nLevel > nMaxLevel) @@ -896,7 +1062,7 @@ These dont work as IPs since they are hardcoded */ // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- - int nCostMod = GetPRCSwitch(X2_CI_CRAFTWAND_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTWAND_COSTMODIFIER); if(nCostMod == 0) nCostMod = 750; int nCost = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_WAND_CASTER_LEVEL); @@ -1027,7 +1193,7 @@ int CICraftCheckCraftStaff(object oSpellTarget, object oCaster, int nSpellID = 0 These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTSTAFF_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTSTAFF_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1175,7 +1341,7 @@ int CICraftCheckCraftRod(object oSpellTarget, object oCaster, int nSpellID = 0) These dont work as IPs since they are hardcoded */ } } - int nCostMod = GetPRCSwitch(X2_CI_CRAFTROD_COSTMODIFIER); + int nCostMod = GetPRCSwitch(PRC_X2_CRAFTROD_COSTMODIFIER); if(!nCostMod) nCostMod = 750; int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID); int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow)); @@ -1544,7 +1710,7 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID, // No point scribing Gems from items, and its not allowed. if (oItem != OBJECT_INVALID) { - FloatingTextStringOnCreature("You cannot scribe a Gem from an item.", oCaster, FALSE); + FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE); return TRUE; } // oTarget here should be the gem. If it's not, fail. @@ -1951,7 +2117,13 @@ int CIGetSpellWasUsedForItemCreation(object oSpellTarget) // ------------------------------------------------- nRet = CICraftCheckCraftStaff(oSpellTarget,oCaster); break; - + + case BASE_ITEM_MUNDANE_HERB : + // ------------------------------------------------- + // Create Infusion + // ------------------------------------------------- + nRet = CICraftCheckCreateInfusion(oSpellTarget,oCaster); + break; // you could add more crafting basetypes here.... } @@ -2740,6 +2912,11 @@ int GetMagicalArtisanFeat(int nCraftingFeat) nReturn = FEAT_MAGICAL_ARTISAN_CRAFT_SKULL_TALISMAN; break; } + case FEAT_CREATE_INFUSION: + { + nReturn = FEAT_MAGICAL_ARTISAN_CREATE_INFUSION; + break; + } default: { if(DEBUG) DoDebug("GetMagicalArtisanFeat: invalid crafting feat"); @@ -2941,6 +3118,306 @@ int GetAlternativeCasterLevel(object oPC, int nLevel) return nLevel; } +// ----------------------------------------------------------------------------- +// Returns TRUE if the player successfully performed Create Infusion +// ----------------------------------------------------------------------------- +int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0) +{ + if (nID == 0) nID = PRCGetSpellId(); + + int bIsSubradial = GetIsSubradialSpell(nID); + + if(bIsSubradial) + { + nID = GetMasterSpellFromSubradial(nID); + } + + // ------------------------------------------------------------------------- + // Check if the caster has the Create Infusion feat + // ------------------------------------------------------------------------- + if (!GetHasFeat(FEAT_CREATE_INFUSION, oCaster)) + { + FloatingTextStrRefOnCreature(40487, oCaster); // Missing feat + return TRUE; + } + + // ------------------------------------------------------------------------- + // Divine spellcasters only + // ------------------------------------------------------------------------- + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can create infusions.", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check if spell is restricted for Create Infusion + // ------------------------------------------------------------------------- + if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_CREATEINFUSION_FEAT_ID)) + { + FloatingTextStrRefOnCreature(83451, oCaster); // Spell not allowed + return TRUE; + } + + // ------------------------------------------------------------------------- + // Optional PnP Herb check + // ------------------------------------------------------------------------- + int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS); + if(bPnPHerbs) + { + int nSpellschool = GetSpellSchool(nID); + int nHerbSchool = GetHerbsSpellSchool(oSpellTarget); + + int nSpellLevel = PRCGetSpellLevelForClass(nID, nClass); + int nHerbLevel = GetHerbsInfusionSpellLevel(oSpellTarget); + + if(nSpellschool != nHerbSchool) + { + // Herb is for wrong spellschool + FloatingTextStringOnCreature("This herb isn't appropriate for this spell school", oCaster); + return TRUE; + } + + if(nSpellLevel > nHerbLevel) + { + // Herb spell circle level too low + FloatingTextStringOnCreature("This herb isn't appropriate for this spell level", oCaster); + return TRUE; + } + } + + // ------------------------------------------------------------------------- + // XP/GP Cost Calculation + // ------------------------------------------------------------------------- + int nLevel = CIGetSpellInnateLevel(nID, TRUE); + int nCostModifier = GetPRCSwitch(PRC_X2_CREATEINFUSION_COSTMODIFIER); + if (nCostModifier == 0) + nCostModifier = 25; + + int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_CREATE_INFUSION_CASTER_LEVEL); + struct craft_cost_struct costs = GetModifiedCostsFromBase(nCost, oCaster, FEAT_CREATE_INFUSION, FALSE); + + // Adjust level for metamagic + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nMetaMagic = PRCGetMetaMagicFeat(); + switch(nMetaMagic) + { + case METAMAGIC_EMPOWER: nLevel += 2; break; + case METAMAGIC_EXTEND: nLevel += 1; break; + case METAMAGIC_MAXIMIZE: nLevel += 3; break; + // Unsupported metamagic IPs not added + } + } + + // ------------------------------------------------------------------------- + // Check Gold + // ------------------------------------------------------------------------- + if (!GetHasGPToSpend(oCaster, costs.nGoldCost)) + { + FloatingTextStrRefOnCreature(3786, oCaster); // Not enough gold + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check XP + // ------------------------------------------------------------------------- + if (!GetHasXPToSpend(oCaster, costs.nXPCost)) + { + FloatingTextStrRefOnCreature(3785, oCaster); // Not enough XP + return TRUE; + } + + // ------------------------------------------------------------------------- + // Check alternative spell emulation requirements + // ------------------------------------------------------------------------- + if (!CheckAlternativeCrafting(oCaster, nID, costs)) + { + FloatingTextStringOnCreature("*Crafting failed!*", oCaster, FALSE); + return TRUE; + } + + // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + // Get the spell's display name from spells.2da via TLK + int nNameStrRef = StringToInt(Get2DAString("spells", "Name", nID)); + string sSpellName = GetStringByStrRef(nNameStrRef); + + // Rename the item + string sNewName = "Infusion of " + sSpellName; + SetName(oInfusion, sNewName); + + // Post-creation actions + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } + +/* // ------------------------------------------------------------------------- + // Create the infused herb item + // ------------------------------------------------------------------------- + object oInfusion = CICreateInfusion(oCaster, nID); + + if (GetIsObjectValid(oInfusion)) + { + SetIdentified(oInfusion, TRUE); + ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0); + SpendXP(oCaster, costs.nXPCost); + SpendGP(oCaster, costs.nGoldCost); + DestroyObject(oSpellTarget); + FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful + + if (!costs.nTimeCost) costs.nTimeCost = 1; + AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost)); + return TRUE; + } + else + { + FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed + FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed + return TRUE; + } */ + + return FALSE; +} + +// ----------------------------------------------------------------------------- +// Create and return an herbal infusion with an item property matching nSpellID +// ----------------------------------------------------------------------------- +object CICreateInfusion(object oCreator, int nSpellID) +{ + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: Entering function"); + + // Keep the original spell id the engine gave us (may be a subradial) + int nSpellOriginal = nSpellID; + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellOriginal is "+IntToString(nSpellOriginal)+"."); + + // Compute the master if this is a subradial. Keep original intact. + int nSpellMaster = nSpellOriginal; + if (GetIsSubradialSpell(nSpellOriginal)) + { + nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); + if (DEBUG) DoDebug("CICreateInfusion: detected subradial " + IntToString(nSpellOriginal) + " master -> " + IntToString(nSpellMaster)); + } + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellMaster is "+IntToString(nSpellMaster)+"."); + + // Try to find an iprp_spells row for the original subradial first (preferred). + int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); + int nSpellUsedForIP = nSpellOriginal; + + // If not found for original, fall back to the master/base spell. + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: no iprp row for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); + nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster); + nSpellUsedForIP = nSpellMaster; + } + + // If still invalid, bail out with a helpful message + if (nPropID < 0) + { + if (DEBUG) DoDebug("CICreateInfusion: No iprp_spells entry for either original " + IntToString(nSpellOriginal) + " or master " + IntToString(nSpellMaster)); + FloatingTextStringOnCreature("This spell cannot be infused (no item property mapping).", oCreator, FALSE); + return OBJECT_INVALID; + } + + if (DEBUG) DoDebug("CICreateInfusion: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property"); + + // Optional: check for material component (use the resolved iprp row) + string sMat = GetMaterialComponentTag(nPropID); + if (sMat != "") + { + object oMat = GetItemPossessedBy(oCreator, sMat); + if (oMat == OBJECT_INVALID) + { + FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component + return OBJECT_INVALID; + } + else + { + DestroyObject(oMat); + } + } + + // Only allow divine spellcasters + int nClass = PRCGetLastSpellCastClass(); + if (!GetIsDivineClass(nClass)) + { + FloatingTextStringOnCreature("Only divine casters can use Create Infusion.", oCreator, FALSE); + return OBJECT_INVALID; + } + + // Create base infusion item (herb) + string sResRef = "prc_infusion_000"; + object oTarget = CreateItemOnObject(sResRef, oCreator); + if (oTarget == OBJECT_INVALID) + { + WriteTimestampedLogEntry("Create Infusion failed: couldn't create item with resref " + sResRef); + return OBJECT_INVALID; + } + + // Confirm that the item is a herb + int nBaseItem = GetBaseItemType(oTarget); + if (nBaseItem != BASE_ITEM_INFUSED_HERB) + { + FloatingTextStringOnCreature("Only herbs may be infused.", oCreator, FALSE); + DestroyObject(oTarget); + return OBJECT_INVALID; + } + + // Remove all non-material item properties from the herb + itemproperty ipRemove = GetFirstItemProperty(oTarget); + while (GetIsItemPropertyValid(ipRemove)) + { + itemproperty ipNext = GetNextItemProperty(oTarget); + if (GetItemPropertyType(ipRemove) != ITEM_PROPERTY_MATERIAL) + RemoveItemProperty(oTarget, ipRemove); + ipRemove = ipNext; + } + + // Add the cast-spell itemproperty using the iprp row we resolved + itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); + AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget); + + // Optional PRC casting metadata: use the SAME spell id that matched the iprp row + // so caster level/DC/meta line up with the actual cast property on the item. + if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL)) + { + int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator)); + // nSpellUsedForIP is either original (if that had an iprp row) or the master (fallback) + itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel); + AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget); + + itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat()); + AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget); + + int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF); + itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC); + AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget); + } + + return oTarget; +} + // Test main -//void main(){} +// void main(){} diff --git a/src/include/prc_x2_itemprop.nss b/src/include/prc_x2_itemprop.nss index e4a1be0..17885cd 100644 --- a/src/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -768,7 +768,6 @@ int IPGetIsBludgeoningWeapon(object oItem) // ---------------------------------------------------------------------------- // Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given // in nSPELL_ID. -// This uses Get2DAstring, so it is slow. Avoid using in loops! // returns -1 if there is no matching property for a spell // ---------------------------------------------------------------------------- int IPGetIPConstCastSpellFromSpellID(int nSpellID) @@ -1883,7 +1882,7 @@ int IPDamageConstant(int nDamBon) case 49: nIPBonus = IP_CONST_DAMAGEBONUS_49; break; case 50: nIPBonus = IP_CONST_DAMAGEBONUS_50; break; } - if (nDamBon > 20) nIPBonus = IP_CONST_DAMAGEBONUS_50; + if (nDamBon > 50) nIPBonus = IP_CONST_DAMAGEBONUS_50; return nIPBonus; } diff --git a/src/include/shd_inc_mystknwn.nss b/src/include/shd_inc_mystknwn.nss index bc6ecc5..b335485 100644 --- a/src/include/shd_inc_mystknwn.nss +++ b/src/include/shd_inc_mystknwn.nss @@ -41,6 +41,7 @@ const string _MYSTERY_LIST_MISC_ARRAY = "_MysteriesKnownMiscArray"; const string _MYSTERY_LIST_LEVEL_ARRAY = "_MysteriesKnownLevelArray_"; const string _MYSTERY_LIST_GENERAL_ARRAY = "_MysteriesKnownGeneralArray"; +#include "shd_inc_shdfunc" ////////////////////////////////////////////////// /* Function prototypes */ diff --git a/src/include/shd_inc_shdfunc.nss b/src/include/shd_inc_shdfunc.nss index 63eb943..6ae4f63 100644 --- a/src/include/shd_inc_shdfunc.nss +++ b/src/include/shd_inc_shdfunc.nss @@ -236,12 +236,12 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS // For when you want to assign the caster level. if(nLevel) { - if(DEBUG) SendMessageToPC(oShadow, "GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); + if(DEBUG) DoDebug("GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel)); //DelayCommand(1.0, DeleteLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE)); return nLevel + nAdjust; } - if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); + if (DEBUG) DoDebug("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow); // The function user needs to know the character's Shadowcaster level in a specific class // instead of whatever the character last shadowcast a mystery as if(nSpecificClass != CLASS_TYPE_INVALID) @@ -288,7 +288,7 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS nLevel -= 4; } - if(DEBUG) FloatingTextStringOnCreature("Shadowcaster Level: " + IntToString(nLevel), oShadow, FALSE); + if(DEBUG) DoDebug("Shadowcaster Level: " + IntToString(nLevel)); return nLevel + nAdjust; } diff --git a/src/include/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/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss index 2785789..92668bf 100644 --- a/src/include/x2_inc_spellhook.nss +++ b/src/include/x2_inc_spellhook.nss @@ -144,8 +144,103 @@ int PRCGetUserSpecificSpellScriptFinished(); #include "pnp_shft_main" #include "inc_dynconv" #include "inc_npc" +#include "inc_infusion" +#include "prc_add_spell_dc" + + +int Spontaneity(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(GetLocalInt(oCaster, "PRC_SpontRegen")) + { + DeleteLocalInt(oCaster, "PRC_SpontRegen"); + + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + + int nRegenSpell; + + if(nCastingClass == CLASS_TYPE_DRUID) + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_RING; break; + case 4: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 7: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 8: nRegenSpell = SPELL_REGEN_CIRCLE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, CLASS_TYPE_DRUID); + } + else + { + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 2: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break; + case 3: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 4: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break; + case 5: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break; + case 6: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break; + case 7: nRegenSpell = SPELL_REGENERATE; break; + case 8: nRegenSpell = SPELL_REGENERATE; break; + case 9: nRegenSpell = SPELL_REGENERATE; break; + } + + ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, nCastingClass); + } + //Don't cast original spell + return FALSE; + } + return TRUE; +} int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) +{ + if(nCastingClass != CLASS_TYPE_DRUID) + return TRUE; + + if(GetLocalInt(oCaster, "PRC_SpontSummon")) + { + DeleteLocalInt(oCaster, "PRC_SpontSummon"); + int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here + int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, CLASS_TYPE_DRUID); + nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic); + int nSummonSpell; + switch(nSpellLevel) + { + case 0: return TRUE; + case 1: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_1; break; + case 2: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_2; break; + case 3: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_3; break; + case 4: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_4; break; + case 5: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_5; break; + case 6: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_6; break; + case 7: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_7; break; + case 8: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_8; break; + case 9: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_9; break; + } + + //:: All SNA spells are subradial spells + SetLocalInt(oCaster, "DomainOrigSpell", nSummonSpell); + SetLocalInt(oCaster, "DomainCastLevel", nSpellLevel); + SetLocalInt(oCaster, "DomainCastClass", CLASS_TYPE_DRUID); + StartDynamicConversation("prc_domain_conv", oCaster, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oCaster); + + //Don't cast original spell + return FALSE; + } + + return TRUE; +} + +/* int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel) { if(nCastingClass != CLASS_TYPE_DRUID) return TRUE; @@ -191,6 +286,8 @@ int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpell return TRUE; } + */ + int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int nMetamagic, string sComponents) { if(!GetIsArcaneClass(nCastingClass)) @@ -904,7 +1001,8 @@ int ShifterCasting(object oCaster, object oSpellCastItem, int nSpellLevel, int n { // Potion drinking is not restricted if(GetBaseItemType(oSpellCastItem) == BASE_ITEM_ENCHANTED_POTION - || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS) + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS + || GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB) return TRUE; //OnHit properties on equipped items not restricted @@ -1441,8 +1539,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_BARD)) return TRUE; if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BARD)) return TRUE; } - else if (bBeguiler) + if (bBeguiler) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Beguiler", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_BEGUILER)) return TRUE; @@ -1492,8 +1591,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) } - else if (bDuskblade) + if (bDuskblade) { + if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Dusblade", oPC); if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_AOTS_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_DUSKBLADE)) return TRUE; @@ -1540,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) @@ -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/module/dlg/nw_g_animal.dlg.json b/src/module/dlg/nw_g_animal.dlg.json index 4a90b21..a65a225 100644 --- a/src/module/dlg/nw_g_animal.dlg.json +++ b/src/module/dlg/nw_g_animal.dlg.json @@ -21,6 +21,10 @@ "value": [ { "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -48,11 +52,15 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "0c_if_scout" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 15 + "value": 439 }, "IsChild": { "type": "byte", @@ -63,7 +71,30 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "0c_if_identify" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 438 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -75,10 +106,14 @@ } }, { - "__struct_id": 2, + "__struct_id": 3, "Active": { "type": "resref", - "value": "" + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -89,30 +124,19 @@ "value": 0 } }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 5 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, { "__struct_id": 4, "Active": { "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 4 + "value": 5 }, "IsChild": { "type": "byte", @@ -125,9 +149,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 3 + "value": 4 }, "IsChild": { "type": "byte", @@ -140,9 +168,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 2 + "value": 3 }, "IsChild": { "type": "byte", @@ -151,10 +183,33 @@ }, { "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 2 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, "Active": { "type": "resref", "value": "nw_d2_intn" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 1 @@ -165,11 +220,15 @@ } }, { - "__struct_id": 8, + "__struct_id": 9, "Active": { "type": "resref", "value": "nw_d2_intl" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 0 @@ -183,7 +242,7 @@ }, "Script": { "type": "resref", - "value": "hench_unbusify" + "value": "" }, "Sound": { "type": "resref", @@ -196,12 +255,17 @@ "Text": { "type": "cexolocstring", "value": { + "0": " You feel warm thoughts from your animal companion, as it wonders what you would like.", "id": 53321 } } }, { "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -247,6 +311,10 @@ }, { "__struct_id": 2, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -292,6 +360,10 @@ }, { "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -337,96 +409,10 @@ }, { "__struct_id": 4, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { + "ActionParams": { "type": "list", "value": [] }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": " The creature looks askance at you. " - } - } - }, - { - "__struct_id": 5, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": " The creature nods its agreement. " - } - } - }, - { - "__struct_id": 6, "Animation": { "type": "dword", "value": 0 @@ -471,7 +457,11 @@ } }, { - "__struct_id": 7, + "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -516,7 +506,11 @@ } }, { - "__struct_id": 8, + "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -561,7 +555,11 @@ } }, { - "__struct_id": 9, + "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -606,7 +604,11 @@ } }, { - "__struct_id": 10, + "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -633,7 +635,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -651,7 +653,11 @@ } }, { - "__struct_id": 11, + "__struct_id": 9, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -678,7 +684,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -696,7 +702,60 @@ } }, { - "__struct_id": 12, + "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [] + }, + "Script": { + "type": "resref", + "value": "nw_ch_fm_st_10" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58463 + } + } + }, + { + "__struct_id": 11, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -736,12 +795,17 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58463 + "0": "The animal seems confused about your actions, but slinks away to appease you.", + "id": 58464 } } }, { - "__struct_id": 13, + "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -786,7 +850,11 @@ } }, { - "__struct_id": 14, + "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -831,7 +899,11 @@ } }, { - "__struct_id": 15, + "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -858,7 +930,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -876,7 +948,11 @@ } }, { - "__struct_id": 16, + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -921,7 +997,11 @@ } }, { - "__struct_id": 17, + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -961,12 +1041,17 @@ "Text": { "type": "cexolocstring", "value": { + "0": "The animal is quite famished and devours the food you offer. The companion seems content.", "id": 58468 } } }, { - "__struct_id": 18, + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -993,7 +1078,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_fm_st_10" + "value": "" }, "Sound": { "type": "resref", @@ -1011,7 +1096,11 @@ } }, { - "__struct_id": 19, + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -1039,11 +1128,15 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 14 + "value": 151 }, "IsChild": { "type": "byte", @@ -1054,11 +1147,71 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + } + ] }, "Index": { "type": "dword", - "value": 13 + "value": 141 }, "IsChild": { "type": "byte", @@ -1069,11 +1222,93 @@ "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_ch_no_stlth" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] }, "Index": { "type": "dword", - "value": 12 + "value": 59 }, "IsChild": { "type": "byte", @@ -1084,11 +1319,93 @@ "__struct_id": 3, "Active": { "type": "resref", - "value": "nw_ch_yes_stlth" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] }, "Index": { "type": "dword", - "value": 11 + "value": 27 }, "IsChild": { "type": "byte", @@ -1099,7 +1416,100 @@ "__struct_id": 4, "Active": { "type": "resref", - "value": "nw_ch_no_srch" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + }, + { + "__struct_id": 7, + "Key": { + "type": "cexostring", + "value": "nClass8" + }, + "Value": { + "type": "cexostring", + "value": "46" + } + } + ] }, "Index": { "type": "dword", @@ -1114,7 +1524,11 @@ "__struct_id": 5, "Active": { "type": "resref", - "value": "nw_ch_yes_srch" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -1129,7 +1543,11 @@ "__struct_id": 6, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -1157,102 +1575,17 @@ "Text": { "type": "cexolocstring", "value": { + "0": " looks up at you, obviously willing to do as you ask.", "id": 58470 } } }, { - "__struct_id": 20, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { + "__struct_id": 19, + "ActionParams": { "type": "list", "value": [] }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Your companion raises his head and nods, no longer paying as much attention to the area around you." - } - } - }, - { - "__struct_id": 21, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Your companion steps from the shadows and returns to view." - } - } - }, - { - "__struct_id": 22, "Animation": { "type": "dword", "value": 0 @@ -1280,11 +1613,27 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] }, "Index": { "type": "dword", - "value": 22 + "value": 26 }, "IsChild": { "type": "byte", @@ -1295,11 +1644,27 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] }, "Index": { "type": "dword", - "value": 21 + "value": 25 }, "IsChild": { "type": "byte", @@ -1310,313 +1675,11 @@ "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_ch_no_stlth" + "value": "x2_hen_tomishad3" }, - "Index": { - "type": "dword", - "value": 20 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "nw_ch_yes_stlth" - }, - "Index": { - "type": "dword", - "value": 19 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "nw_ch_no_srch" - }, - "Index": { - "type": "dword", - "value": 18 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_ch_yes_srch" - }, - "Index": { - "type": "dword", - "value": 17 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 6, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 16 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58470 - } - } - }, - { - "__struct_id": 23, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Your companion looks up at you a nods, now paying less attention to the area around you." - } - } - }, - { - "__struct_id": 24, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Your companion steps from the shadows and returns to view." - } - } - }, - { - "__struct_id": 25, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 15 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 6 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 5 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 4 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 3 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_d2_intn" + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -1627,11 +1690,452 @@ "value": 0 } }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 21 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, { "__struct_id": 6, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 17 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 16 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 15 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 14 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 13 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 12 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 11 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " waits for you to tell it what to summon." + } + } + }, + { + "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -1641,6 +2145,25 @@ "type": "byte", "value": 0 } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 0 + } } ] }, @@ -1659,12 +2182,13778 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58471 + "0": "You sure?", + "id": 87721 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 58 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 48 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 38 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 7 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Ready to cast it waits for your command.", + "id": 88866 + } + } + }, + { + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 37 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 36 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 47 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 46 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 45 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 44 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 43 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 42 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 41 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 40 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 39 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 57 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 54 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 53 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 52 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 51 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 50 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 49 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 140 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 139 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 130 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 129 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 128 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 127 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 126 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 125 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 124 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 123 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 122 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 121 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 120 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 119 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 116 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 115 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 16, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 114 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 17, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 113 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 18, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 112 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 19, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 111 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 20, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 110 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 21, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 109 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 22, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 108 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 23, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 107 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 24, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 106 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 25, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 105 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 26, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 104 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 27, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 103 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 28, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 102 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 29, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 101 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 30, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 100 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 31, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 99 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 32, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 98 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 33, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 97 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 34, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 96 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 35, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 95 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 36, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 94 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 37, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 93 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 38, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 92 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 39, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 91 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 40, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 90 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 41, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 89 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 42, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 88 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 43, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 87 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 44, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 86 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 45, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 85 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 46, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 84 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 47, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 83 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 48, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 82 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 49, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 81 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 50, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 80 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 51, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 79 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 52, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 78 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 53, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 77 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 54, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 76 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 55, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 75 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 56, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 74 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 57, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 73 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 58, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 72 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 59, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 71 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 60, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 70 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 61, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 69 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 62, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 68 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 63, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 67 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 64, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 66 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 65, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 65 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 66, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 64 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 67, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 63 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 68, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 62 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 69, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 70, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 71, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 72, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "At the ready your companion listens.", + "id": 87720 } } }, { "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 118 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 117 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "You sure?", + "id": 87721 + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 138 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 137 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 136 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 135 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 134 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 133 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 132 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 131 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Okay. Who shoulds I cast it on?", + "id": 87722 + } + } + }, + { + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 150 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 149 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 148 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 147 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 146 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 145 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 144 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 143 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 142 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Looking at you it waits.", + "id": 87722 + } + } + }, + { + "__struct_id": 29, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 180 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 179 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 178 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_pickuploot" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 177 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 170 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 159 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 158 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 157 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_skillrank" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSkill" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nRank" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 153 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " looks at you awaiting your instructions on tactics." + } + } + }, + { + "__struct_id": 30, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 156 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 155 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 154 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Looking around, it listens for you to tell them how to deal with objects." + } + } + }, + { + "__struct_id": 31, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 169 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 168 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 167 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 166 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 165 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 164 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 163 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_cntrspell" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 162 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 161 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 160 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Your companion looks up to the sky while you tell it how to use magic." + } + } + }, + { + "__struct_id": 32, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 176 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 175 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 174 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 173 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 172 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 171 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Looking at you, waits for instructon on how it should heal.", + "id": 55427 + } + } + }, + { + "__struct_id": 33, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 437 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_defensive" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 436 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ambusher" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 435 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ranged" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 187 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_peaceful" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 186 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_taunt" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 185 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_taunt" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 184 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 183 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_assoc_mode" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nMode" + }, + "Value": { + "type": "cexostring", + "value": "16384" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 182 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 181 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Your companion listens intently for your combat tactics." + } + } + }, + { + "__struct_id": 34, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 434 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_defensive" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 433 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ambusher" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 432 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ranged" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 187 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 431 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_taunt" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 430 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 429 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 428 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 427 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 426 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What do you think is the best tactic?" + } + } + }, + { + "__struct_id": 35, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 425 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 424 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 423 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_pickuploot" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 422 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 415 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 403 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 402 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 401 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 397 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What do you have in mind?" + } + } + }, + { + "__struct_id": 36, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 38 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_scout" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 396 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_identify" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 395 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_open_inven" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 391 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 380 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 298 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 266 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + }, + { + "__struct_id": 7, + "Key": { + "type": "cexostring", + "value": "nClass8" + }, + "Value": { + "type": "cexostring", + "value": "46" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 251 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 195 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_hen_leave" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 192 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_convo" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 191 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What would you like to discuss?" + } + } + }, + { + "__struct_id": 37, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 194 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 193 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Are you sure you want to do that?" + } + } + }, + { + "__struct_id": 38, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_polymorph" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 250 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "305" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 244 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "304" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 239 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "898" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 233 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "900" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 229 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "901" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 225 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "903" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 221 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "902" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 217 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "1060" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 213 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "1061" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 209 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "257" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 208 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "x2_d2_haslayon" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 198 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "x2_d1_dmight" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 197 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "x2_d1_dshield" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 196 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let's see what I can do...", + "id": 95904 + } + } + }, + { + "__struct_id": 39, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 207 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 206 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 205 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 204 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 201 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 200 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And who should be the target of my healing?", + "id": 87722 + } + } + }, + { + "__struct_id": 40, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 212 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 211 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 210 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 41, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 216 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 215 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 214 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 42, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 220 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 219 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 218 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 43, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 224 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 223 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 222 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 44, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 228 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 227 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 226 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 45, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 232 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 231 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 230 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 46, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 238 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 237 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 236 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 235 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 234 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 47, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 243 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 242 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 241 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 240 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 48, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 249 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 248 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 247 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 246 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 245 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 49, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 265 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 264 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x2_hen_tomishad3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 263 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 262 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 261 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 260 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 259 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 258 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 257 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 256 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 255 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 254 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 253 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 252 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What would you have me summon?" + } + } + }, + { + "__struct_id": 50, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 297 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 287 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 277 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 267 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What would you like to discuss about my defensive spells?", + "id": 88866 + } + } + }, + { + "__struct_id": 51, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 276 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 275 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 274 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 273 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 272 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 271 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 270 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 269 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 268 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 52, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 286 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 285 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 284 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 283 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 282 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 281 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 280 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 279 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 278 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 53, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 296 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 295 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 294 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 293 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 292 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 291 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 290 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 289 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 288 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 54, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 379 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 378 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 369 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 368 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 367 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 366 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 365 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 364 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 363 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 362 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 361 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 360 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 359 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 358 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 355 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 354 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 16, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 353 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 17, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 352 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 18, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 351 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 19, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 350 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 20, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 349 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 21, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 348 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 22, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 347 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 23, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 346 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 24, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 345 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 25, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 344 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 26, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 343 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 27, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 342 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 28, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 341 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 29, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 340 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 30, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 339 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 31, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 338 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 32, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 337 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 33, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 336 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 34, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 335 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 35, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 334 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 36, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 333 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 37, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 332 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 38, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 331 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 39, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 330 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 40, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 329 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 41, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 328 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 42, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 327 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 43, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 326 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 44, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 325 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 45, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 324 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 46, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 323 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 47, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 322 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 48, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 321 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 49, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 320 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 50, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 319 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 51, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 318 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 52, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 317 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 53, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 316 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 54, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 315 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 55, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 314 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 56, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 313 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 57, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 312 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 58, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 311 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 59, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 310 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 60, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 309 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 61, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 308 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 62, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 307 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 63, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 306 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 64, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 305 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 65, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 304 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 66, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 303 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 67, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 302 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 68, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 301 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 69, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 300 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 70, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 299 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 71, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 381 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What you want me to cast?", + "id": 87720 + } + } + }, + { + "__struct_id": 55, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 357 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 356 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "You sure?", + "id": 87721 + } + } + }, + { + "__struct_id": 56, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 377 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 376 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 375 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 374 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 373 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 372 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 371 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 370 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 381 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Okay. Who shoulds I cast it on?", + "id": 87722 + } + } + }, + { + "__struct_id": 57, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 390 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 389 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 388 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 387 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 386 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 385 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 384 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 383 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 382 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 381 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And who should be the target of my healing?", + "id": 87722 + } + } + }, + { + "__struct_id": 58, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 394 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 393 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 392 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sure, what would you like me to do?" + } + } + }, + { + "__struct_id": 59, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_skillrank" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSkill" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nRank" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 400 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_skillrank" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSkill" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nRank" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 399 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 398 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Should I do something else?" + } + } + }, + { + "__struct_id": 60, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 414 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 413 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_a_magic_m" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nMode" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 412 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 411 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 410 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 409 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 408 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 407 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_cntrspell" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 406 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 405 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 404 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " How would you like me to use magic in combat?" + } + } + }, + { + "__struct_id": 61, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 421 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 420 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 419 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 418 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 417 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 416 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " When do you think I should heal our allies?", + "id": 55427 + } + } + }, + { + "__struct_id": 62, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -1704,6 +15993,7 @@ "Text": { "type": "cexolocstring", "value": { + "0": "The creature looks at you strangely and resumes what it was doing before.", "id": 53320 } } @@ -1712,17 +16002,21 @@ }, "NumWords": { "type": "dword", - "value": 592 + "value": 2384 }, "PreventZoomIn": { "type": "byte", - "value": 0 + "value": 1 }, "ReplyList": { "type": "list", "value": [ { "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -1748,6 +16042,10 @@ "type": "resref", "value": "nw_ch_fm_st_03" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 3 @@ -1767,6 +16065,10 @@ "type": "resref", "value": "nw_ch_fm_st_04" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 2 @@ -1786,6 +16088,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 1 @@ -1816,13 +16122,16 @@ "Text": { "type": "cexolocstring", "value": { - "0": "Nothing right now.", "id": 53319 } } }, { "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -1848,6 +16157,10 @@ "type": "resref", "value": "nw_ch_fm_st_03" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 3 @@ -1863,6 +16176,10 @@ "type": "resref", "value": "nw_ch_fm_st_04" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 2 @@ -1878,6 +16195,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 1 @@ -1910,78 +16231,10 @@ }, { "__struct_id": 2, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { + "ActionParams": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "henchscoutyes" - }, - "Index": { - "type": "dword", - "value": 5 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "henchscoutno" - }, - "Index": { - "type": "dword", - "value": 4 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] + "value": [] }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "henchscout" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Scout ahead for enemies. Engage in combat if they are nearby; otherwise return to me." - } - } - }, - { - "__struct_id": 3, "Animation": { "type": "dword", "value": 1 @@ -2007,9 +16260,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 12 + "value": 10 }, "IsChild": { "type": "byte", @@ -2022,9 +16279,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 11 + "value": 9 }, "IsChild": { "type": "byte", @@ -2037,9 +16298,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 10 + "value": 8 }, "IsChild": { "type": "byte", @@ -2052,9 +16317,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 9 + "value": 7 }, "IsChild": { "type": "byte", @@ -2067,9 +16336,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 8 + "value": 6 }, "IsChild": { "type": "byte", @@ -2082,9 +16355,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 7 + "value": 5 }, "IsChild": { "type": "byte", @@ -2097,9 +16374,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 6 + "value": 4 }, "IsChild": { "type": "byte", @@ -2128,7 +16409,11 @@ } }, { - "__struct_id": 4, + "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -2152,11 +16437,34 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_09" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 13 + "value": 12 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 11 }, "IsChild": { "type": "byte", @@ -2185,7 +16493,11 @@ } }, { - "__struct_id": 5, + "__struct_id": 4, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -2211,9 +16523,13 @@ "type": "resref", "value": "nw_ch_fm_st_03" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 16 + "value": 15 }, "IsChild": { "type": "byte", @@ -2226,9 +16542,13 @@ "type": "resref", "value": "nw_ch_fm_st_04" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 15 + "value": 14 }, "IsChild": { "type": "byte", @@ -2241,9 +16561,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 14 + "value": 13 }, "IsChild": { "type": "byte", @@ -2272,7 +16596,11 @@ } }, { - "__struct_id": 6, + "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -2298,9 +16626,13 @@ "type": "resref", "value": "nw_ch_fm_st_11" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 18 + "value": 17 }, "IsChild": { "type": "byte", @@ -2313,9 +16645,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 17 + "value": 16 }, "IsChild": { "type": "byte", @@ -2344,7 +16680,11 @@ } }, { - "__struct_id": 7, + "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -2370,6 +16710,272 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Me needs you to do something for me.", + "id": 58440 + } + } + }, + { + "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I would like you to do something different for me.", + "id": 58441 + } + } + }, + { + "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Nevermind." + } + } + }, + { + "__struct_id": 9, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets do something else." + } + } + }, + { + "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 19 @@ -2396,132 +17002,28 @@ "Text": { "type": "cexolocstring", "value": { - "0": "I need you to do something else.", - "id": 58441 + "0": "I need you to summon something if you can." } } }, { - "__struct_id": 8, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { + "__struct_id": 11, + "ActionParams": { "type": "list", "value": [ { "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_03" - }, - "Index": { - "type": "dword", - "value": 3 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { + "Key": { "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_04" + "value": "nSpell" }, - "Index": { - "type": "dword", - "value": 2 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { + "Value": { "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 1 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": "178" } } ] }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Nevermind.", - "id": 58442 - } - } - }, - { - "__struct_id": 9, "Animation": { "type": "dword", "value": 0 @@ -2547,6 +17049,830 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IX.", + "id": 88353 + } + } + }, + { + "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VIII.", + "id": 88354 + } + } + }, + { + "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VII.", + "id": 88355 + } + } + }, + { + "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VI.", + "id": 88356 + } + } + }, + { + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature V.", + "id": 88358 + } + } + }, + { + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IV.", + "id": 88358 + } + } + }, + { + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature III.", + "id": 88359 + } + } + }, + { + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature II.", + "id": 88360 + } + } + }, + { + "__struct_id": 19, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature I.", + "id": 88361 + } + } + }, + { + "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Create Undead.", + "id": 88425 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 20 @@ -2564,7 +17890,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_srch_off" + "value": "0c_h_cast_spell" }, "Sound": { "type": "resref", @@ -2573,15 +17899,20 @@ "Text": { "type": "cexolocstring", "value": { - "0": "You can stop searching all the time now." + "0": "Animate Dead.", + "id": 88446 } } }, { - "__struct_id": 10, + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -2597,27 +17928,7 @@ }, "EntriesList": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] + "value": [] }, "Quest": { "type": "cexostring", @@ -2625,7 +17936,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_srch_on" + "value": "" }, "Sound": { "type": "resref", @@ -2634,13 +17945,245 @@ "Text": { "type": "cexolocstring", "value": { - "0": "I need you to be on the alert.", - "id": 58444 + "0": "No, I've changed my mind.", + "id": 88415 } } }, { - "__struct_id": 11, + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "Henchmen" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_hen_tomishad4" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Shadow." + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Familiar." + } + } + }, + { + "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Companion." + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -2666,6 +18209,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 21 @@ -2683,7 +18230,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_stlth_off" + "value": "" }, "Sound": { "type": "resref", @@ -2692,15 +18239,20 @@ "Text": { "type": "cexolocstring", "value": { - "0": "You can return from the shadows now." + "0": "Let us talk about your defensive spells.", + "id": 89061 } } }, { - "__struct_id": 12, + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -2723,191 +18275,9 @@ "type": "resref", "value": "" }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_stlth_on" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I want you to remain hidden more.", - "id": 58446 - } - } - }, - { - "__struct_id": 13, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_18" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I want you to hang further back from me.", - "id": 58448 - } - } - }, - { - "__struct_id": 14, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_6" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I need you to stay closer to me.", - "id": 58450 - } - } - }, - { - "__struct_id": 15, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -2935,15 +18305,43 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58441 + "0": "Cast all your defensive spells.", + "id": 89063 } } }, { - "__struct_id": 16, + "__struct_id": 29, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -2959,84 +18357,7 @@ }, "EntriesList": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_03" - }, - "Index": { - "type": "dword", - "value": 3 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_04" - }, - "Index": { - "type": "dword", - "value": 2 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 1 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] + "value": [] }, "Quest": { "type": "cexostring", @@ -3044,7 +18365,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "0c_henchmenspell" }, "Sound": { "type": "resref", @@ -3053,12 +18374,569 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58443 + "0": "Cast on all the party members.", + "id": 88431 } } }, { - "__struct_id": 17, + "__struct_id": 30, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 31, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 32, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 33, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 34, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 35, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 36, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 37, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 38, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3084,6 +18962,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 23 @@ -3101,7 +18983,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_srch_off" + "value": "" }, "Sound": { "type": "resref", @@ -3110,15 +18992,43 @@ "Text": { "type": "cexolocstring", "value": { - "0": "You can stop searching all the time now." + "0": "Cast all your long duration defensive spells.", + "id": 89064 } } }, { - "__struct_id": 18, + "__struct_id": 39, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -3134,27 +19044,7 @@ }, "EntriesList": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] + "value": [] }, "Quest": { "type": "cexostring", @@ -3162,7 +19052,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_srch_on" + "value": "0c_henchmenspell" }, "Sound": { "type": "resref", @@ -3171,12 +19061,569 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58445 + "0": "Cast on all the party members.", + "id": 88431 } } }, { - "__struct_id": 19, + "__struct_id": 40, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 41, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 42, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 43, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 44, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 45, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 46, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 47, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 48, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3202,6 +19649,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 24 @@ -3219,7 +19670,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_stlth_off" + "value": "" }, "Sound": { "type": "resref", @@ -3228,16 +19679,654 @@ "Text": { "type": "cexolocstring", "value": { - "0": "You can return from the shadows now." + "0": "Cast all your short duration defensive spells.", + "id": 89065 } } }, { - "__struct_id": 20, + "__struct_id": 49, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, "Animation": { "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", "value": 1 }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 50, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 51, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 52, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 53, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 54, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 55, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 56, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 57, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 58, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, "AnimLoop": { "type": "byte", "value": 1 @@ -3259,9 +20348,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 25 + "value": 21 }, "IsChild": { "type": "byte", @@ -3280,7 +20373,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_stlth_on" + "value": "0c_assoc_actions" }, "Sound": { "type": "resref", @@ -3289,15 +20382,19 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58447 + "0": "Change if you cast long duration spells after resting." } } }, { - "__struct_id": 21, + "__struct_id": 59, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -3320,66 +20417,9 @@ "type": "resref", "value": "" }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_18" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58449 - } - } - }, - { - "__struct_id": 22, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -3398,7 +20438,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_dist_6" + "value": "" }, "Sound": { "type": "resref", @@ -3407,15 +20447,32 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58451 + "0": "I need you to cast a spell.", + "id": 88348 } } }, { - "__struct_id": 23, + "__struct_id": 60, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, "Animation": { "type": "dword", - "value": 1 + "value": 0 }, "AnimLoop": { "type": "byte", @@ -3436,11 +20493,15 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_ch_fm_st_03" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 3 + "value": 26 }, "IsChild": { "type": "byte", @@ -3450,16 +20511,4781 @@ "type": "cexostring", "value": "" } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wounding Whispers.", + "id": 88350 + } + } + }, + { + "__struct_id": 61, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ultravision.", + "id": 88351 + } + } + }, + { + "__struct_id": 62, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "True Seeing.", + "id": 88352 + } + } + }, + { + "__struct_id": 63, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stoneskin.", + "id": 88362 + } + } + }, + { + "__struct_id": 64, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Resistance.", + "id": 88363 + } + } + }, + { + "__struct_id": 65, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Mantle.", + "id": 88364 + } + } + }, + { + "__struct_id": 66, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield of Faith.", + "id": 88365 + } + } + }, + { + "__struct_id": 67, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield.", + "id": 88366 + } + } + }, + { + "__struct_id": 68, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shadow Shield.", + "id": 88367 + } + } + }, + { + "__struct_id": 69, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "See Invisibility.", + "id": 88368 + } + } + }, + { + "__struct_id": 70, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sanctuary.", + "id": 88369 + } + } + }, + { + "__struct_id": 71, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Restoration.", + "id": 88370 + } + } + }, + { + "__struct_id": 72, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resistance.", + "id": 88371 + } + } + }, + { + "__struct_id": 73, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resist Elements.", + "id": 88372 + } + } + }, + { + "__struct_id": 74, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Paralysis.", + "id": 88373 + } + } + }, + { + "__struct_id": 75, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Fear.", + "id": 88374 + } + } + }, + { + "__struct_id": 76, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Disease.", + "id": 88375 + } + } + }, + { + "__struct_id": 77, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Curse.", + "id": 88376 + } + } + }, + { + "__struct_id": 78, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Blindness/Deafness.", + "id": 88377 + } + } + }, + { + "__struct_id": 79, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Regenerate.", + "id": 88378 + } + } + }, + { + "__struct_id": 80, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Spells.", + "id": 88379 + } + } + }, + { + "__struct_id": 81, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Evil." + } + } + }, + { + "__struct_id": 82, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Elements.", + "id": 88380 + } + } + }, + { + "__struct_id": 83, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Premonition.", + "id": 88381 + } + } + }, + { + "__struct_id": 84, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Prayer.", + "id": 88382 + } + } + }, + { + "__struct_id": 85, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Owl's Wisdom.", + "id": 88383 + } + } + }, + { + "__struct_id": 86, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Neutralize poison.", + "id": 88384 + } + } + }, + { + "__struct_id": 87, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Monstrous Regeneration.", + "id": 88385 + } + } + }, + { + "__struct_id": 88, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minor Globe of Invulnerability.", + "id": 88386 + } + } + }, + { + "__struct_id": 89, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mind Blank.", + "id": 88387 + } + } + }, + { + "__struct_id": 90, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mass Haste.", + "id": 88388 + } + } + }, + { + "__struct_id": 91, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Magical Vestment.", + "id": 88389 + } + } + }, + { + "__struct_id": 92, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mage Armor.", + "id": 88390 + } + } + }, + { + "__struct_id": 93, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Light.", + "id": 88391 + } + } + }, + { + "__struct_id": 94, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Spell Mantle.", + "id": 88392 + } + } + }, + { + "__struct_id": 95, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Restoration.", + "id": 88393 + } + } + }, + { + "__struct_id": 96, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Mind Blank", + "id": 88394 + } + } + }, + { + "__struct_id": 97, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Dispel.", + "id": 88395 + } + } + }, + { + "__struct_id": 98, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Knock.", + "id": 88396 + } + } + }, + { + "__struct_id": 99, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility Sphere.", + "id": 88397 + } + } + }, + { + "__struct_id": 100, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility", + "id": 88398 + } + } + }, + { + "__struct_id": 101, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Improved Invisibility.", + "id": 88399 + } + } + }, + { + "__struct_id": 102, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Haste.", + "id": 88400 + } + } + }, + { + "__struct_id": 103, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Stoneskin.", + "id": 88401 + } + } + }, + { + "__struct_id": 104, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Spell Mantle.", + "id": 88402 + } + } + }, + { + "__struct_id": 105, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Sanctuary.", + "id": 88403 + } + } + }, + { + "__struct_id": 106, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Restoration.", + "id": 88404 + } + } + }, + { + "__struct_id": 107, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Magic Weapon.", + "id": 88405 + } + } + }, + { + "__struct_id": 108, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Dispelling.", + "id": 88406 + } + } + }, + { + "__struct_id": 109, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Globe of Invulnerability.", + "id": 88407 + } + } + }, + { + "__struct_id": 110, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ghostly Visage.", + "id": 88408 + } + } + }, + { + "__struct_id": 111, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Freedom of Movement.", + "id": 88409 + } + } + }, + { + "__struct_id": 112, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fox's Cunning", + "id": 88410 + } + } + }, + { + "__struct_id": 113, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Find Traps.", + "id": 88411 + } + } + }, + { + "__struct_id": 114, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ethereal Visage.", + "id": 88412 + } + } + }, + { + "__struct_id": 115, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Entropic Shield.", + "id": 88413 + } + } + }, + { + "__struct_id": 116, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Energy Buffer.", + "id": 88414 + } + } + }, + { + "__struct_id": 117, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I've changed my mind.", + "id": 88415 + } + } + }, + { + "__struct_id": 118, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } }, { "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 119, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_ch_fm_st_04" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 2 + "value": 27 }, "IsChild": { "type": "byte", @@ -3469,17 +25295,2445 @@ "type": "cexostring", "value": "" } - }, + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endure Elements.", + "id": 88417 + } + } + }, + { + "__struct_id": 120, + "ActionParams": { + "type": "list", + "value": [ { - "__struct_id": 2, + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, "Active": { "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", "value": 1 }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endurance.", + "id": 88418 + } + } + }, + { + "__struct_id": 121, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Elemental Shield.", + "id": 88419 + } + } + }, + { + "__struct_id": 122, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Eagle's Splendour.", + "id": 88420 + } + } + }, + { + "__struct_id": 123, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Power.", + "id": 88421 + } + } + }, + { + "__struct_id": 124, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dispel Magic.", + "id": 88422 + } + } + }, + { + "__struct_id": 125, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Ward.", + "id": 88423 + } + } + }, + { + "__struct_id": 126, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Armor.", + "id": 88424 + } + } + }, + { + "__struct_id": 127, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Continual Flame.", + "id": 88426 + } + } + }, + { + "__struct_id": 128, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Clarity.", + "id": 88427 + } + } + }, + { + "__struct_id": 129, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cat's Grace.", + "id": 88428 + } + } + }, + { + "__struct_id": 130, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bull's Strength.", + "id": 88429 + } + } + }, + { + "__struct_id": 131, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 132, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 133, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 134, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 135, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 136, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 137, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 138, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 139, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bless.", + "id": 88445 + } + } + }, + { + "__struct_id": 140, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Aid.", + "id": 88447 + } + } + }, + { + "__struct_id": 141, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a healing spell." + } + } + }, + { + "__struct_id": 142, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Heal up the whole party.", + "id": 88431 + } + } + }, + { + "__struct_id": 143, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 144, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 145, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 146, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "Target" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 147, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 148, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 149, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 150, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 151, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to discuss your tactics." + } + } + }, + { + "__struct_id": 152, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 18 + }, "IsChild": { "type": "byte", "value": 1 @@ -3506,12 +27760,1529 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58452 + "0": "Lets talk about something else." } } }, { - "__struct_id": 24, + "__struct_id": 153, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets discuss how you deal with objects." + } + } + }, + { + "__struct_id": 154, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Bash" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your bashing tactics.", + "id": 96501 + } + } + }, + { + "__struct_id": 155, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Locks" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your lock picking tactics.", + "id": 96501 + } + } + }, + { + "__struct_id": 156, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Traps" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your trap tactics.", + "id": 96502 + } + } + }, + { + "__struct_id": 157, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Search" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your search tactics." + } + } + }, + { + "__struct_id": 158, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Stealth" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your stealth tactics." + } + } + }, + { + "__struct_id": 159, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let's change how you use magic in combat." + } + } + }, + { + "__struct_id": 160, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you use magic items or not.", + "id": 96498 + } + } + }, + { + "__struct_id": 161, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Dispel" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your dispel tactics.", + "id": 96500 + } + } + }, + { + "__struct_id": 162, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stop countering the enemies spells.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 163, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 164, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BuffFirst" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change who you cast defensive spells on first.", + "id": 96500 + } + } + }, + { + "__struct_id": 165, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "OffensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast offensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 166, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast defensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 167, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "NoMagic" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change how you use magic spells in combat." + } + } + }, + { + "__struct_id": 168, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic more in combat." + } + } + }, + { + "__struct_id": 169, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic less in combat." + } + } + }, + { + "__struct_id": 170, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -3535,11 +29306,117 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_ch_fm_st_03" + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] }, "Index": { "type": "dword", - "value": 3 + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change when you decide to heal me.", + "id": 54985 + } + } + }, + { + "__struct_id": 171, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 }, "IsChild": { "type": "byte", @@ -3549,16 +29426,5265 @@ "type": "cexostring", "value": "" } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal out of combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 172, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health an one needs for you to heal out of combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 173, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal during combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 174, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health any one needs for you to heal during combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 175, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealSelf" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal yourself.", + "id": 54990 + } + } + }, + { + "__struct_id": 176, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealAllies" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal any allies.", + "id": 54989 + } + } + }, + { + "__struct_id": 177, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Pickup" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change if you retrieve items and gold." + } + } + }, + { + "__struct_id": 178, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowFarther" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow farther away from me.", + "id": 96508 + } + } + }, + { + "__struct_id": 179, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowCloser" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow closer to me.", + "id": 96508 + } + } + }, + { + "__struct_id": 180, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about your tactics in combat." + } + } + }, + { + "__struct_id": 181, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AttackTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you fight every opponent during combat." + } + } + }, + { + "__struct_id": 182, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AtkAssociates" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your tactics against familiars, companions, and summons." + } + } + }, + { + "__struct_id": 183, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Ranged" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your ranged combat tactics." + } + } + }, + { + "__struct_id": 184, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!" + } + } + }, + { + "__struct_id": 185, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Taunt" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to taunt the enemy!" + } + } + }, + { + "__struct_id": 186, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "PeaceTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Don't engage in combat." + } + } + }, + { + "__struct_id": 187, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RangedTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use agressive ranged tactics, stay out of melee.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 188, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "That will be all for now." + } + } + }, + { + "__struct_id": 189, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to discuss how we can work together." + } + } + }, + { + "__struct_id": 190, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 36 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about something else." + } + } + }, + { + "__struct_id": 191, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_get_convo" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let us talk about something completely different." + } + } + }, + { + "__struct_id": 192, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 37 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "We should part ways." + } + } + }, + { + "__struct_id": 193, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I like having you around." + } + } + }, + { + "__struct_id": 194, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_fire_henchmen" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes I'm sure, Perhapse we'll meet again." + } + } + }, + { + "__struct_id": 195, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 38 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you use a special ability?", + "id": 96382 + } + } + }, + { + "__struct_id": 196, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_d2_dshield" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Shield.", + "id": 96383 + } + } + }, + { + "__struct_id": 197, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_d2_dmight" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Might.", + "id": 96384 + } + } + }, + { + "__struct_id": 198, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 39 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lay on Hands.", + "id": 96385 + } + } + }, + { + "__struct_id": 199, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I've changed my mind.", + "id": 88430 + } + } + }, + { + "__struct_id": 200, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } }, { "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 201, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 202, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 203, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 204, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 205, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 206, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 207, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 208, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "257" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_use_feat" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your bard song.", + "id": 88342 + } + } + }, + { + "__struct_id": 209, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_ch_fm_st_04" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 2 + "value": 40 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your construction shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 210, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "740" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Iron Golem" + } + } + }, + { + "__struct_id": 211, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "739" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Demon Flesh Golem" + } + } + }, + { + "__struct_id": 212, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "738" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stone Golem" + } + } + }, + { + "__struct_id": 213, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 41 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your outsider shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 214, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "735" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Slaad" + } + } + }, + { + "__struct_id": 215, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "734" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Rakshasa" + } + } + }, + { + "__struct_id": 216, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "733" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Azer" + } + } + }, + { + "__struct_id": 217, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 42 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your humanoid shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 218, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "684" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Kobold Assasin" + } + } + }, + { + "__struct_id": 219, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "683" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lizard folk" + } + } + }, + { + "__struct_id": 220, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "682" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Drow" + } + } + }, + { + "__struct_id": 221, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 43 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape V.", + "id": 88342 + } + } + }, + { + "__struct_id": 222, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "691" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mindflayer" + } + } + }, + { + "__struct_id": 223, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "679" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Medusa" + } + } + }, + { + "__struct_id": 224, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "694" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dire Tiger" + } + } + }, + { + "__struct_id": 225, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 44 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape III.", + "id": 88342 + } + } + }, + { + "__struct_id": 226, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "674" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Manticore" + } + } + }, + { + "__struct_id": 227, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "673" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Drider" + } + } + }, + { + "__struct_id": 228, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "670" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Basilisk" + } + } + }, + { + "__struct_id": 229, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 45 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape II.", + "id": 88342 + } + } + }, + { + "__struct_id": 230, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "680" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minotaur" + } + } + }, + { + "__struct_id": 231, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "678" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Gargoyle" + } + } + }, + { + "__struct_id": 232, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "672" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Harpy" + } + } + }, + { + "__struct_id": 233, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 46 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape I.", + "id": 88342 + } + } + }, + { + "__struct_id": 234, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "662" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Green Wyrmling" + } + } + }, + { + "__struct_id": 235, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "661" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "White Wyrmling" + } + } + }, + { + "__struct_id": 236, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "660" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Black Wyrmling" + } + } + }, + { + "__struct_id": 237, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "659" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Blue Wyrmling" + } + } + }, + { + "__struct_id": 238, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "658" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Red Wyrmling" + } + } + }, + { + "__struct_id": 239, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 47 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your elemental shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 240, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "398" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Water" + } + } + }, + { + "__struct_id": 241, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "397" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fire" + } + } + }, + { + "__struct_id": 242, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "399" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Earth" + } + } + }, + { + "__struct_id": 243, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "400" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Air" + } + } + }, + { + "__struct_id": 244, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 48 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your wild shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 245, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "405" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Badger" + } + } + }, + { + "__struct_id": 246, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "404" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Boar" + } + } + }, + { + "__struct_id": 247, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "403" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wolf" + } + } + }, + { + "__struct_id": 248, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "402" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Panther" + } + } + }, + { + "__struct_id": 249, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "401" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bear" + } + } + }, + { + "__struct_id": 250, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nEffectType" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 36 }, "IsChild": { "type": "byte", @@ -3568,17 +34694,10049 @@ "type": "cexostring", "value": "" } - }, + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_remove_effect" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Transform back into your natural form.", + "id": 96384 + } + } + }, + { + "__struct_id": 251, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ { - "__struct_id": 2, + "__struct_id": 0, "Active": { "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", + "value": 49 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to summon something if you can." + } + } + }, + { + "__struct_id": 252, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", "value": 1 }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IX.", + "id": 88353 + } + } + }, + { + "__struct_id": 253, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VIII.", + "id": 88354 + } + } + }, + { + "__struct_id": 254, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VII.", + "id": 88355 + } + } + }, + { + "__struct_id": 255, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VI.", + "id": 88356 + } + } + }, + { + "__struct_id": 256, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature V.", + "id": 88358 + } + } + }, + { + "__struct_id": 257, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IV.", + "id": 88358 + } + } + }, + { + "__struct_id": 258, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature III.", + "id": 88359 + } + } + }, + { + "__struct_id": 259, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature II.", + "id": 88360 + } + } + }, + { + "__struct_id": 260, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature I.", + "id": 88361 + } + } + }, + { + "__struct_id": 261, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Create Undead.", + "id": 88425 + } + } + }, + { + "__struct_id": 262, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Animate Dead.", + "id": 88446 + } + } + }, + { + "__struct_id": 263, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_hen_tomishad4" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Shadow." + } + } + }, + { + "__struct_id": 264, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Familiar." + } + } + }, + { + "__struct_id": 265, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Companion." + } + } + }, + { + "__struct_id": 266, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 50 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let us talk about your defensive spells.", + "id": 89061 + } + } + }, + { + "__struct_id": 267, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 51 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your defensive spells.", + "id": 89063 + } + } + }, + { + "__struct_id": 268, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 269, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 270, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 271, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 272, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 273, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 274, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 275, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 276, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 277, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 52 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your long duration defensive spells.", + "id": 89064 + } + } + }, + { + "__struct_id": 278, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 279, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 280, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 281, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 282, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 283, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 284, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 285, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 286, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 287, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 53 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your short duration defensive spells.", + "id": 89065 + } + } + }, + { + "__struct_id": 288, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 289, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 290, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 291, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 292, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 293, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 294, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 295, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 296, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 297, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 50 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast long duration spells after resting." + } + } + }, + { + "__struct_id": 298, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 54 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a spell.", + "id": 88348 + } + } + }, + { + "__struct_id": 299, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wounding Whispers.", + "id": 88350 + } + } + }, + { + "__struct_id": 300, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ultravision.", + "id": 88351 + } + } + }, + { + "__struct_id": 301, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "True Seeing.", + "id": 88352 + } + } + }, + { + "__struct_id": 302, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stoneskin.", + "id": 88362 + } + } + }, + { + "__struct_id": 303, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Resistance.", + "id": 88363 + } + } + }, + { + "__struct_id": 304, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Mantle.", + "id": 88364 + } + } + }, + { + "__struct_id": 305, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield of Faith.", + "id": 88365 + } + } + }, + { + "__struct_id": 306, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield.", + "id": 88366 + } + } + }, + { + "__struct_id": 307, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shadow Shield.", + "id": 88367 + } + } + }, + { + "__struct_id": 308, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "See Invisibility.", + "id": 88368 + } + } + }, + { + "__struct_id": 309, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sanctuary.", + "id": 88369 + } + } + }, + { + "__struct_id": 310, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Restoration.", + "id": 88370 + } + } + }, + { + "__struct_id": 311, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resistance.", + "id": 88371 + } + } + }, + { + "__struct_id": 312, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resist Elements.", + "id": 88372 + } + } + }, + { + "__struct_id": 313, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Paralysis.", + "id": 88373 + } + } + }, + { + "__struct_id": 314, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Fear.", + "id": 88374 + } + } + }, + { + "__struct_id": 315, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Disease.", + "id": 88375 + } + } + }, + { + "__struct_id": 316, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Curse.", + "id": 88376 + } + } + }, + { + "__struct_id": 317, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Blindness/Deafness.", + "id": 88377 + } + } + }, + { + "__struct_id": 318, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Regenerate.", + "id": 88378 + } + } + }, + { + "__struct_id": 319, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Spells.", + "id": 88379 + } + } + }, + { + "__struct_id": 320, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Evil." + } + } + }, + { + "__struct_id": 321, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Elements.", + "id": 88380 + } + } + }, + { + "__struct_id": 322, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Premonition.", + "id": 88381 + } + } + }, + { + "__struct_id": 323, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Prayer.", + "id": 88382 + } + } + }, + { + "__struct_id": 324, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Owl's Wisdom.", + "id": 88383 + } + } + }, + { + "__struct_id": 325, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Neutralize poison.", + "id": 88384 + } + } + }, + { + "__struct_id": 326, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Monstrous Regeneration.", + "id": 88385 + } + } + }, + { + "__struct_id": 327, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minor Globe of Invulnerability.", + "id": 88386 + } + } + }, + { + "__struct_id": 328, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mind Blank.", + "id": 88387 + } + } + }, + { + "__struct_id": 329, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mass Haste.", + "id": 88388 + } + } + }, + { + "__struct_id": 330, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Magical Vestment.", + "id": 88389 + } + } + }, + { + "__struct_id": 331, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mage Armor.", + "id": 88390 + } + } + }, + { + "__struct_id": 332, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Light.", + "id": 88391 + } + } + }, + { + "__struct_id": 333, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Spell Mantle.", + "id": 88392 + } + } + }, + { + "__struct_id": 334, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Restoration.", + "id": 88393 + } + } + }, + { + "__struct_id": 335, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Mind Blank", + "id": 88394 + } + } + }, + { + "__struct_id": 336, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Dispel.", + "id": 88395 + } + } + }, + { + "__struct_id": 337, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Knock.", + "id": 88396 + } + } + }, + { + "__struct_id": 338, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility Sphere.", + "id": 88397 + } + } + }, + { + "__struct_id": 339, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility", + "id": 88398 + } + } + }, + { + "__struct_id": 340, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Improved Invisibility.", + "id": 88399 + } + } + }, + { + "__struct_id": 341, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Haste.", + "id": 88400 + } + } + }, + { + "__struct_id": 342, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Stoneskin.", + "id": 88401 + } + } + }, + { + "__struct_id": 343, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Spell Mantle.", + "id": 88402 + } + } + }, + { + "__struct_id": 344, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Sanctuary.", + "id": 88403 + } + } + }, + { + "__struct_id": 345, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Restoration.", + "id": 88404 + } + } + }, + { + "__struct_id": 346, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Magic Weapon.", + "id": 88405 + } + } + }, + { + "__struct_id": 347, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Dispelling.", + "id": 88406 + } + } + }, + { + "__struct_id": 348, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Globe of Invulnerability.", + "id": 88407 + } + } + }, + { + "__struct_id": 349, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ghostly Visage.", + "id": 88408 + } + } + }, + { + "__struct_id": 350, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Freedom of Movement.", + "id": 88409 + } + } + }, + { + "__struct_id": 351, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fox's Cunning", + "id": 88410 + } + } + }, + { + "__struct_id": 352, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Find Traps.", + "id": 88411 + } + } + }, + { + "__struct_id": 353, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ethereal Visage.", + "id": 88412 + } + } + }, + { + "__struct_id": 354, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Entropic Shield.", + "id": 88413 + } + } + }, + { + "__struct_id": 355, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Energy Buffer.", + "id": 88414 + } + } + }, + { + "__struct_id": 356, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I've changed my mind.", + "id": 88415 + } + } + }, + { + "__struct_id": 357, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 358, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endure Elements.", + "id": 88417 + } + } + }, + { + "__struct_id": 359, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endurance.", + "id": 88418 + } + } + }, + { + "__struct_id": 360, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Elemental Shield.", + "id": 88419 + } + } + }, + { + "__struct_id": 361, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Eagle's Splendour.", + "id": 88420 + } + } + }, + { + "__struct_id": 362, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Power.", + "id": 88421 + } + } + }, + { + "__struct_id": 363, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dispel Magic.", + "id": 88422 + } + } + }, + { + "__struct_id": 364, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Ward.", + "id": 88423 + } + } + }, + { + "__struct_id": 365, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Armor.", + "id": 88424 + } + } + }, + { + "__struct_id": 366, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Continual Flame.", + "id": 88426 + } + } + }, + { + "__struct_id": 367, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Clarity.", + "id": 88427 + } + } + }, + { + "__struct_id": 368, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cat's Grace.", + "id": 88428 + } + } + }, + { + "__struct_id": 369, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bull's Strength.", + "id": 88429 + } + } + }, + { + "__struct_id": 370, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 371, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 372, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 373, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 374, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 375, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 376, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 377, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 378, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bless.", + "id": 88445 + } + } + }, + { + "__struct_id": 379, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Aid.", + "id": 88447 + } + } + }, + { + "__struct_id": 380, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 57 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a healing spell." + } + } + }, + { + "__struct_id": 381, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 36 + }, "IsChild": { "type": "byte", "value": 1 @@ -3605,7 +44763,4858 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58453 + "0": "I've changed my mind.", + "id": 88430 + } + } + }, + { + "__struct_id": 382, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Heal up the whole party.", + "id": 88431 + } + } + }, + { + "__struct_id": 383, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 384, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 385, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 386, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 387, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 388, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 389, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 390, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 391, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 58 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can we talk about your items?" + } + } + }, + { + "__struct_id": 392, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "GiveMagicItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Give me all the magical items in your inventory.", + "id": 96514 + } + } + }, + { + "__struct_id": 393, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "GiveUnIdentifiedItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Give me all your unidentified items.", + "id": 96514 + } + } + }, + { + "__struct_id": 394, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x0_d1_hen_inven" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to adjust your equipment.", + "id": 96514 + } + } + }, + { + "__struct_id": 395, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x1_hen_identify" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you identify our equipment?", + "id": 88341 + } + } + }, + { + "__struct_id": 396, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Scout" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I would like you to scout the area." + } + } + }, + { + "__struct_id": 397, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 59 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets discuss how you deal with objects." + } + } + }, + { + "__struct_id": 398, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Bash" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 59 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your bashing tactics.", + "id": 96507 + } + } + }, + { + "__struct_id": 399, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Locks" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 59 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your lock picking tactics.", + "id": 96507 + } + } + }, + { + "__struct_id": 400, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Traps" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 59 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your trap tactics.", + "id": 96502 + } + } + }, + { + "__struct_id": 401, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Search" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your search tactics.", + "id": 96505 + } + } + }, + { + "__struct_id": 402, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Stealth" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your stealth tactics.", + "id": 96505 + } + } + }, + { + "__struct_id": 403, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let's change how you use magic in combat." + } + } + }, + { + "__struct_id": 404, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you use magic items or not.", + "id": 96498 + } + } + }, + { + "__struct_id": 405, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Dispel" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your dispel tactics.", + "id": 96500 + } + } + }, + { + "__struct_id": 406, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stop countering the enemies spells.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 407, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Counter the enemy spells!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 408, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BuffFirst" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change who you cast defensive spells on first.", + "id": 96500 + } + } + }, + { + "__struct_id": 409, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "OffensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Only cast offensive spells for now.", + "id": 96498 + } + } + }, + { + "__struct_id": 410, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Only cast defensive spells for now.", + "id": 96498 + } + } + }, + { + "__struct_id": 411, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "NoMagic" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Don't use any magic until I say otherwise.", + "id": 96497 + } + } + }, + { + "__struct_id": 412, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "UseMagic" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use any magic spells you have.", + "id": 96498 + } + } + }, + { + "__struct_id": 413, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic more in combat." + } + } + }, + { + "__struct_id": 414, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic less in combat." + } + } + }, + { + "__struct_id": 415, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change when you should heal.", + "id": 54985 + } + } + }, + { + "__struct_id": 416, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal out of combat.", + "id": 54990 + } + } + }, + { + "__struct_id": 417, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health an one needs for you to heal out of combat.", + "id": 54989 + } + } + }, + { + "__struct_id": 418, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal during combat.", + "id": 54990 + } + } + }, + { + "__struct_id": 419, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health any one needs for you to heal during combat.", + "id": 54989 + } + } + }, + { + "__struct_id": 420, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealSelf" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal yourself.", + "id": 54989 + } + } + }, + { + "__struct_id": 421, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealAllies" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal any allies.", + "id": 54989 + } + } + }, + { + "__struct_id": 422, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Pickup" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change if you pickup items and gold." + } + } + }, + { + "__struct_id": 423, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowFarther" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow farther away from me.", + "id": 96510 + } + } + }, + { + "__struct_id": 424, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowCloser" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow closer to me.", + "id": 96511 + } + } + }, + { + "__struct_id": 425, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about your tactics in combat." + } + } + }, + { + "__struct_id": 426, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AttackTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you fight every opponent during combat.", + "2": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"", + "3": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"" + } + } + }, + { + "__struct_id": 427, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AtkAssociates" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your tactics against familiars, companions, and summons.", + "id": 62531 + } + } + }, + { + "__struct_id": 428, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Ranged" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your ranged combat tactics.", + "id": 62531 + } + } + }, + { + "__struct_id": 429, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 430, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Taunt" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to taunt the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 431, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "PeaceTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Don't engage in combat.", + "2": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"", + "3": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"" + } + } + }, + { + "__struct_id": 432, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AmbushTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use ambush tactics, hide and then strike.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 433, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use defensive tactics to protect yourself.", + "id": 62532 + } + } + }, + { + "__struct_id": 434, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your best judgement in combat.", + "id": 62531 + } + } + }, + { + "__struct_id": 435, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AmbushTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use ambush tactics, hide and then strike.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 436, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use defensive tactics protect yourself.", + "id": 62532 + } + } + }, + { + "__struct_id": 437, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use basic combat tactics.", + "id": 62531 + } + } + }, + { + "__struct_id": 438, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x1_hen_identify" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you identify my equipment?", + "id": 88341 + } + } + }, + { + "__struct_id": 439, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Scout" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I would like you to scout the area." } } } @@ -3620,16 +49629,36 @@ "type": "resref", "value": "nw_ch_ac_st_01" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 26 + "value": 62 } }, { "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_ch_ac_st_02" + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] }, "Index": { "type": "dword", diff --git a/src/module/dlg/nw_g_fam.dlg.json b/src/module/dlg/nw_g_fam.dlg.json index 67cacd6..5be0aae 100644 --- a/src/module/dlg/nw_g_fam.dlg.json +++ b/src/module/dlg/nw_g_fam.dlg.json @@ -21,6 +21,10 @@ "value": [ { "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -50,9 +54,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 35 + "value": 193 }, "IsChild": { "type": "byte", @@ -63,11 +71,15 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "0c_if_scout" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 20 + "value": 192 }, "IsChild": { "type": "byte", @@ -78,11 +90,15 @@ "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "0c_if_identify" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 6 + "value": 191 }, "IsChild": { "type": "byte", @@ -93,11 +109,15 @@ "__struct_id": 3, "Active": { "type": "resref", - "value": "" + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 5 + "value": 7 }, "IsChild": { "type": "byte", @@ -108,11 +128,15 @@ "__struct_id": 4, "Active": { "type": "resref", - "value": "" + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 4 + "value": 6 }, "IsChild": { "type": "byte", @@ -125,9 +149,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 3 + "value": 5 }, "IsChild": { "type": "byte", @@ -140,9 +168,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 2 + "value": 4 }, "IsChild": { "type": "byte", @@ -153,7 +185,49 @@ "__struct_id": 7, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 3 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 2 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -165,10 +239,14 @@ } }, { - "__struct_id": 8, + "__struct_id": 10, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -183,7 +261,7 @@ }, "Script": { "type": "resref", - "value": "hench_unbusify" + "value": "" }, "Sound": { "type": "resref", @@ -196,12 +274,17 @@ "Text": { "type": "cexolocstring", "value": { + "0": " What do you require of me ?", "id": 58490 } } }, { "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -247,6 +330,10 @@ }, { "__struct_id": 2, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -292,6 +379,10 @@ }, { "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -318,7 +409,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -337,6 +428,10 @@ }, { "__struct_id": 4, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -382,6 +477,10 @@ }, { "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -408,7 +507,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -427,6 +526,10 @@ }, { "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -472,6 +575,10 @@ }, { "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -498,7 +605,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -517,6 +624,10 @@ }, { "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -562,6 +673,10 @@ }, { "__struct_id": 9, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -588,7 +703,7 @@ }, "Script": { "type": "resref", - "value": "" + "value": "nw_ch_fm_st_10" }, "Sound": { "type": "resref", @@ -607,6 +722,10 @@ }, { "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -633,7 +752,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_fm_st-11" + "value": "" }, "Sound": { "type": "resref", @@ -652,6 +771,10 @@ }, { "__struct_id": 11, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -678,7 +801,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_fm_st-11" + "value": "" }, "Sound": { "type": "resref", @@ -697,6 +820,10 @@ }, { "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -742,6 +869,10 @@ }, { "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -787,6 +918,10 @@ }, { "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -812,99 +947,9 @@ "value": [] }, "Script": { - "type": "resref", - "value": "nw_ch_fm_st_12" - }, - "Sound": { "type": "resref", "value": "" }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58504 - } - } - }, - { - "__struct_id": 15, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "nw_ch_fm_st_10" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58505 - } - } - }, - { - "__struct_id": 16, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "nw_ch_fm_st_10" - }, "Sound": { "type": "resref", "value": "" @@ -921,7 +966,11 @@ } }, { - "__struct_id": 17, + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -966,7 +1015,11 @@ } }, { - "__struct_id": 18, + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -993,7 +1046,7 @@ }, "Script": { "type": "resref", - "value": "nw_ch_fm_st_10" + "value": "" }, "Sound": { "type": "resref", @@ -1011,7 +1064,11 @@ } }, { - "__struct_id": 19, + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -1055,8 +1112,110 @@ } } }, + { + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [] + }, + "Script": { + "type": "resref", + "value": "nw_ch_fm_st_12" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58504 + } + } + }, + { + "__struct_id": 19, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58505 + } + } + }, { "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -1084,11 +1243,15 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 19 + "value": 151 }, "IsChild": { "type": "byte", @@ -1099,11 +1262,71 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intl" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + } + ] }, "Index": { "type": "dword", - "value": 18 + "value": 141 }, "IsChild": { "type": "byte", @@ -1114,11 +1337,93 @@ "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_ch_no_stlth" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] }, "Index": { "type": "dword", - "value": 17 + "value": 59 }, "IsChild": { "type": "byte", @@ -1129,1092 +1434,89 @@ "__struct_id": 3, "Active": { "type": "resref", - "value": "nw_ch_yes_stlth" - }, - "Index": { - "type": "dword", - "value": 16 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "nw_ch_no_srch" - }, - "Index": { - "type": "dword", - "value": 15 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_ch_yes_srch" - }, - "Index": { - "type": "dword", - "value": 14 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 6, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 8 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 7, - "Active": { - "type": "resref", - "value": "nw_d2_intl" - }, - "Index": { - "type": "dword", - "value": 7 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58510 - } - } - }, - { - "__struct_id": 21, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 13 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 12 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 11 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 10 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 9 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Tell me what to do; I will obey you." - } - } - }, - { - "__struct_id": 22, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam4" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "My life is forfeit then, o Master. I will try my best." - } - } - }, - { - "__struct_id": 23, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam3" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I will try to be brave and join the fight with you always!" - } - } - }, - { - "__struct_id": 24, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam2" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "As you command---I wil try to fight and run away when it gets scary!" - } - } - }, - { - "__struct_id": 25, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam1" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I will avoid danger, attacking only the weakest enemies." - } - } - }, - { - "__struct_id": 26, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam0" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Thank you ! I am honored that you care for my wishes!" - } - } - }, - { - "__struct_id": 27, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "As you desire, . I shall stop being so watchful.", - "id": 58511 - } - } - }, - { - "__struct_id": 28, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I shall return from the shadows, ...", - "id": 58512 - } - } - }, - { - "__struct_id": 29, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 33 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 32 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_ch_no_stlth" - }, - "Index": { - "type": "dword", - "value": 31 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "nw_ch_no_srch" - }, - "Index": { - "type": "dword", - "value": 29 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 22 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 21 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58516 - } - } - }, - { - "__struct_id": 30, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 33 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 32 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_ch_no_stlth" - }, - "Index": { - "type": "dword", - "value": 31 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "nw_ch_no_srch" - }, - "Index": { - "type": "dword", - "value": 29 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 22 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 21 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58517 - } - } - }, - { - "__struct_id": 31, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 33 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 32 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_ch_no_stlth" - }, - "Index": { - "type": "dword", - "value": 31 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "nw_ch_yes_stlth" - }, - "Index": { - "type": "dword", - "value": 30 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "nw_ch_no_srch" - }, - "Index": { - "type": "dword", - "value": 29 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "nw_ch_yes_srch" - }, - "Index": { - "type": "dword", - "value": 28 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 6, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 22 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 7, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 21 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58510 - } - } - }, - { - "__struct_id": 32, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] }, "Index": { "type": "dword", @@ -2226,10 +1528,223 @@ } }, { - "__struct_id": 1, + "__struct_id": 4, "Active": { "type": "resref", - "value": "" + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + }, + { + "__struct_id": 7, + "Key": { + "type": "cexostring", + "value": "nClass8" + }, + "Value": { + "type": "cexostring", + "value": "46" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What would you like me to do, my ?", + "id": 58510 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] }, "Index": { "type": "dword", @@ -2241,10 +1756,26 @@ } }, { - "__struct_id": 2, + "__struct_id": 1, "Active": { "type": "resref", - "value": "" + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] }, "Index": { "type": "dword", @@ -2256,10 +1787,14 @@ } }, { - "__struct_id": 3, + "__struct_id": 2, "Active": { "type": "resref", - "value": "" + "value": "x2_hen_tomishad3" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -2270,12 +1805,430 @@ "value": 0 } }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 21 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, { "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 17 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 16 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 15 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 14 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 13 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 12 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 11 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, "Active": { "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What would you have me summon?" + } + } + }, + { + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 23 @@ -2284,614 +2237,20 @@ "type": "byte", "value": 0 } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Tell me what to do; I will obey you." - } - } - }, - { - "__struct_id": 33, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam4" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "My life is forfeit then, o Master. I will try my best." - } - } - }, - { - "__struct_id": 34, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam3" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I will try to be brave and join the fight with you always!" - } - } - }, - { - "__struct_id": 35, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam2" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "As you command---I wil try to fight and run away when it gets scary!" - } - } - }, - { - "__struct_id": 36, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam1" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I will avoid danger, attacking only the weakest enemies." - } - } - }, - { - "__struct_id": 37, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [] - }, - "Script": { - "type": "resref", - "value": "henchfam0" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Thank you ! I am honored that you care for my wishes!" - } - } - }, - { - "__struct_id": 38, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ + }, { - "__struct_id": 0, + "__struct_id": 1, "Active": { "type": "resref", "value": "" }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "As you desire, . I shall stop being so watchful.", - "id": 58511 - } - } - }, - { - "__struct_id": 39, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58511 - } - } - }, - { - "__struct_id": 40, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I shall return from the shadows, ...", - "id": 58512 - } - } - }, - { - "__struct_id": 41, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58512 - } - } - }, - { - "__struct_id": 42, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58513 - } - } - }, - { - "__struct_id": 43, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 34 + "value": 22 }, "IsChild": { "type": "byte", @@ -2915,12 +2274,17 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58514 + "0": "You sure?", + "id": 87721 } } }, { - "__struct_id": 44, + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -2948,19 +2312,19 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 20 + "value": 58 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { @@ -2969,17 +2333,17 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 5 + "value": 48 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { @@ -2988,17 +2352,17 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 4 + "value": 38 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { @@ -3007,28 +2371,32 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 3 + "value": 28 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 4, "Active": { "type": "resref", - "value": "" + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 2 + "value": 7 }, "IsChild": { "type": "byte", @@ -3038,35 +2406,4058 @@ "type": "cexostring", "value": "" } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What would you like to discuss about my defensive spells?", + "id": 88866 + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 37 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 36 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 0 + } }, { "__struct_id": 5, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 0 + "value": 32 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 47 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 46 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 45 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 44 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 43 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 42 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 41 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 40 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 39 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 57 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 54 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 53 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 52 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 51 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 50 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "x2_d1_targetall" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 49 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 140 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 139 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 130 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 129 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 128 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 127 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 126 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 125 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 124 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 123 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 122 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 121 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 120 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 119 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 116 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 115 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 16, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 114 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 17, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 113 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 18, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 112 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 19, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 111 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 20, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 110 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 21, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 109 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 22, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 108 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 23, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 107 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 24, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 106 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 25, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 105 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 26, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 104 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 27, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 103 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 28, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 102 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 29, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 101 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 30, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 100 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 31, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 99 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 32, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 98 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 33, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 97 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 34, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 96 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 35, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 95 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 36, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 94 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 37, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 93 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 38, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 92 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 39, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 91 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 40, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 90 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 41, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 89 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 42, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 88 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 43, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 87 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 44, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 86 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 45, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 85 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 46, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 84 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 47, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 83 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 48, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 82 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 49, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 81 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 50, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 80 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 51, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 79 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 52, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 78 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 53, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 77 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 54, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 76 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 55, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 75 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 56, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 74 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 57, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 73 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 58, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 72 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 59, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 71 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 60, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 70 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 61, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 69 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 62, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 68 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 63, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 67 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 64, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 66 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 65, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 65 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 66, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 64 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 67, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 63 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 68, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 62 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 69, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 70, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 71, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What you want me to cast?", + "id": 87720 + } + } + }, + { + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 118 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 117 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "You sure?", + "id": 87721 + } + } + }, + { + "__struct_id": 29, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 138 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 137 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 136 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 135 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 134 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 133 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 132 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 131 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Okay. Who shoulds I cast it on?", + "id": 87722 + } + } + }, + { + "__struct_id": 30, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 150 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 149 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 148 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 147 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 146 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 145 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 144 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 143 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 142 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And who should be the target of my healing?", + "id": 87722 + } + } + }, + { + "__struct_id": 31, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 180 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 179 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 178 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_pickuploot" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 177 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 170 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 159 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 158 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 157 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 153 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, "Active": { "type": "resref", "value": "nw_d2_intl" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 1 + "value": 8 }, "IsChild": { "type": "byte", @@ -3094,12 +6485,16 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58515 + "0": " What tactic would you like me to change, ?" } } }, { - "__struct_id": 45, + "__struct_id": 32, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3127,68 +6522,72 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 33 + "value": 156 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 32 + "value": 155 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_ch_no_stlth" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 31 + "value": 154 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 3, "Active": { "type": "resref", - "value": "nw_ch_no_srch" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 29 + "value": 151 }, "IsChild": { "type": "byte", @@ -3201,32 +6600,17 @@ }, { "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 22 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, "Active": { "type": "resref", "value": "nw_d2_intn" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 21 + "value": 9 }, "IsChild": { "type": "byte", @@ -3254,12 +6638,16 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58516 + "0": " My benignant , how can I change my actions?\"" } } }, { - "__struct_id": 46, + "__struct_id": 33, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3287,76 +6675,76 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 33 + "value": 169 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_d2_intn" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 32 + "value": 168 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 2, "Active": { "type": "resref", - "value": "nw_ch_no_stlth" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 31 + "value": 167 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { "__struct_id": 3, "Active": { "type": "resref", - "value": "nw_ch_no_srch" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 29 + "value": 166 }, "IsChild": { "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" + "value": 0 } }, { @@ -3365,9 +6753,139 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 22 + "value": 165 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 164 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 163 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_cntrspell" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 162 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 161 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 160 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 }, "IsChild": { "type": "byte", @@ -3379,14 +6897,18 @@ } }, { - "__struct_id": 5, + "__struct_id": 11, "Active": { "type": "resref", "value": "nw_d2_intn" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 21 + "value": 9 }, "IsChild": { "type": "byte", @@ -3414,12 +6936,16 @@ "Text": { "type": "cexolocstring", "value": { - "id": 58517 + "0": " Almighty , how shall I use magic in combat?" } } }, { - "__struct_id": 47, + "__struct_id": 34, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3449,9 +6975,604 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 36 + "value": 176 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 175 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 174 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 173 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 172 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 171 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Let me know when to heal, all knowning .", + "id": 55427 + } + } + }, + { + "__struct_id": 35, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_defensive" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ambusher" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ranged" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 187 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_peaceful" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 186 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_taunt" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 185 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 184 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 183 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 182 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 181 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "nw_d2_intn" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "nw_d2_intl" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Oh powerful ! How would you like to change my tactics?" + } + } + }, + { + "__struct_id": 36, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 194 }, "IsChild": { "type": "byte", @@ -3480,7 +7601,11 @@ } }, { - "__struct_id": 48, + "__struct_id": 37, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3510,9 +7635,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 37 + "value": 195 }, "IsChild": { "type": "byte", @@ -3541,7 +7670,11 @@ } }, { - "__struct_id": 49, + "__struct_id": 38, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -3586,441 +7719,11 @@ } }, { - "__struct_id": 50, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { + "__struct_id": 39, + "ActionParams": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 35 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 20 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_d2_intl" - }, - "Index": { - "type": "dword", - "value": 6 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 5 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 4 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 3 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 6, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 2 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 7, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 0 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 8, - "Active": { - "type": "resref", - "value": "nw_d2_intl" - }, - "Index": { - "type": "dword", - "value": 1 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] + "value": [] }, - "Script": { - "type": "resref", - "value": "hench_unbusify" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58518 - } - } - }, - { - "__struct_id": 51, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "RepliesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 35 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 20 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_d2_intl" - }, - "Index": { - "type": "dword", - "value": 6 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 5 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 4, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 4 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 5, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 3 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 6, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 2 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 7, - "Active": { - "type": "resref", - "value": "nw_d2_intn" - }, - "Index": { - "type": "dword", - "value": 0 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - }, - { - "__struct_id": 8, - "Active": { - "type": "resref", - "value": "nw_d2_intl" - }, - "Index": { - "type": "dword", - "value": 1 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Script": { - "type": "resref", - "value": "hench_unbusify" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Speaker": { - "type": "cexostring", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58519 - } - } - }, - { - "__struct_id": 52, "Animation": { "type": "dword", "value": 0 @@ -4068,17 +7771,21 @@ }, "NumWords": { "type": "dword", - "value": 983 + "value": 1302 }, "PreventZoomIn": { "type": "byte", - "value": 0 + "value": 1 }, "ReplyList": { "type": "list", "value": [ { "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -4104,6 +7811,79 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 1 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58472 + } + } + }, + { + "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 1 @@ -4134,70 +7914,12 @@ } } }, - { - "__struct_id": 1, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 1 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Nothing right now.", - "id": 58472 - } - } - }, { "__struct_id": 2, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -4223,6 +7945,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 9 @@ -4238,6 +7964,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 8 @@ -4253,6 +7983,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 7 @@ -4268,6 +8002,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 6 @@ -4283,6 +8021,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 5 @@ -4298,6 +8040,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 4 @@ -4313,6 +8059,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 3 @@ -4328,6 +8078,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 2 @@ -4360,6 +8114,10 @@ }, { "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -4385,6 +8143,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 13 @@ -4400,6 +8162,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 12 @@ -4415,6 +8181,10 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 11 @@ -4430,6 +8200,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 10 @@ -4462,78 +8236,10 @@ }, { "__struct_id": 4, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { + "ActionParams": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_11" - }, - "Index": { - "type": "dword", - "value": 15 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 14 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] + "value": [] }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58476 - } - } - }, - { - "__struct_id": 5, "Animation": { "type": "dword", "value": 1 @@ -4559,9 +8265,13 @@ "type": "resref", "value": "nw_ch_fm_st_04" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 19 + "value": 17 }, "IsChild": { "type": "byte", @@ -4574,9 +8284,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 18 + "value": 16 }, "IsChild": { "type": "byte", @@ -4589,9 +8303,13 @@ "type": "resref", "value": "nw_ch_fm_st_09" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 17 + "value": 15 }, "IsChild": { "type": "byte", @@ -4604,9 +8322,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 16 + "value": 14 }, "IsChild": { "type": "byte", @@ -4635,7 +8357,11 @@ } }, { - "__struct_id": 6, + "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -4659,11 +8385,15 @@ "__struct_id": 0, "Active": { "type": "resref", - "value": "nw_ch_fm_st_03" + "value": "nw_ch_fm_st_11" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 30 + "value": 19 }, "IsChild": { "type": "byte", @@ -4674,23 +8404,146 @@ "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_ch_fm_st_04" + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", - "value": 29 + "value": 18 }, "IsChild": { "type": "byte", "value": 0 } - }, + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58476 + } + } + }, + { + "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ { - "__struct_id": 2, + "__struct_id": 0, "Active": { "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "id": 58478 + } + } + }, + { + "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 20 @@ -4717,13 +8570,17 @@ "Text": { "type": "cexolocstring", "value": { - "0": "I need you to change what you're doing.", + "0": "I need you to change how you are doing things.", "id": 58479 } } }, { - "__struct_id": 7, + "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -4749,6 +8606,10 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", "value": 1 @@ -4783,350 +8644,12 @@ } } }, - { - "__struct_id": 8, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 21 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You makin boo boos. You do somefin diffent way?" - } - } - }, { "__struct_id": 9, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { + "ActionParams": { "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 22 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] + "value": [] }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Stop you being wimp eh? We fight.. Die if we haf ta!" - } - } - }, - { - "__struct_id": 10, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 23 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You big toughy. Stay wif me always, unless you dun in big trouble." - } - } - }, - { - "__struct_id": 11, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 24 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You fight lots wif me. All but dem real nasty ones." - } - } - }, - { - "__struct_id": 12, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 25 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You dun keep get hurt. Leave em all but the little uns." - } - } - }, - { - "__struct_id": 13, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 26 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You do what you fink is good eh." - } - } - }, - { - "__struct_id": 14, "Animation": { "type": "dword", "value": 1 @@ -5152,452 +8675,9 @@ "type": "resref", "value": "" }, - "Index": { - "type": "dword", - "value": 27 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_srch_off" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You dun go real slow. Stop lookin around so much eh?", - "id": 58483 - } - } - }, - { - "__struct_id": 15, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 39 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_srch_on" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58482 - } - } - }, - { - "__struct_id": 16, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 28 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_stlth_off" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Where is you? Come back where me can see you.", - "id": 58485 - } - } - }, - { - "__struct_id": 17, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 41 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_stlth_on" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58484 - } - } - }, - { - "__struct_id": 18, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 42 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_18" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58486 - } - } - }, - { - "__struct_id": 19, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 43 - }, - "IsChild": { - "type": "byte", - "value": 1 - }, - "LinkComment": { - "type": "cexostring", - "value": "" - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_6" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58488 - } - } - }, - { - "__struct_id": 20, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_03" - }, - "Index": { - "type": "dword", - "value": 46 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 1, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_04" - }, - "Index": { - "type": "dword", - "value": 45 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 31 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58479 - } - } - }, - { - "__struct_id": 21, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -5634,7 +8714,11 @@ } }, { - "__struct_id": 22, + "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 0 @@ -5660,6 +8744,10869 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 21 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to summon something if you can." + } + } + }, + { + "__struct_id": 11, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IX.", + "id": 88353 + } + } + }, + { + "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VIII.", + "id": 88354 + } + } + }, + { + "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VII.", + "id": 88355 + } + } + }, + { + "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VI.", + "id": 88356 + } + } + }, + { + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature V.", + "id": 88358 + } + } + }, + { + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IV.", + "id": 88358 + } + } + }, + { + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature III.", + "id": 88359 + } + } + }, + { + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature II.", + "id": 88360 + } + } + }, + { + "__struct_id": 19, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature I.", + "id": 88361 + } + } + }, + { + "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Create Undead.", + "id": 88425 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Animate Dead.", + "id": 88446 + } + } + }, + { + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I've changed my mind.", + "id": 88415 + } + } + }, + { + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_hen_tomishad4" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Shadow." + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Familiar." + } + } + }, + { + "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Companion." + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let us talk about your defensive spells.", + "id": 89061 + } + } + }, + { + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your defensive spells.", + "id": 89063 + } + } + }, + { + "__struct_id": 29, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 30, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 31, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 32, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 33, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 34, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 35, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 36, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 37, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 38, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your long duration defensive spells.", + "id": 89064 + } + } + }, + { + "__struct_id": 39, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 40, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 41, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 42, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 43, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 44, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 45, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 46, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 47, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 48, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your short duration defensive spells.", + "id": 89065 + } + } + }, + { + "__struct_id": 49, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 50, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 51, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 52, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 53, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 54, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 55, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 56, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 57, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 58, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast long duration spells after resting." + } + } + }, + { + "__struct_id": 59, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a spell.", + "id": 88348 + } + } + }, + { + "__struct_id": 60, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wounding Whispers.", + "id": 88350 + } + } + }, + { + "__struct_id": 61, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ultravision.", + "id": 88351 + } + } + }, + { + "__struct_id": 62, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "True Seeing.", + "id": 88352 + } + } + }, + { + "__struct_id": 63, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stoneskin.", + "id": 88362 + } + } + }, + { + "__struct_id": 64, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Resistance.", + "id": 88363 + } + } + }, + { + "__struct_id": 65, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Mantle.", + "id": 88364 + } + } + }, + { + "__struct_id": 66, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield of Faith.", + "id": 88365 + } + } + }, + { + "__struct_id": 67, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield.", + "id": 88366 + } + } + }, + { + "__struct_id": 68, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shadow Shield.", + "id": 88367 + } + } + }, + { + "__struct_id": 69, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "See Invisibility.", + "id": 88368 + } + } + }, + { + "__struct_id": 70, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sanctuary.", + "id": 88369 + } + } + }, + { + "__struct_id": 71, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Restoration.", + "id": 88370 + } + } + }, + { + "__struct_id": 72, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resistance.", + "id": 88371 + } + } + }, + { + "__struct_id": 73, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resist Elements.", + "id": 88372 + } + } + }, + { + "__struct_id": 74, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Paralysis.", + "id": 88373 + } + } + }, + { + "__struct_id": 75, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Fear.", + "id": 88374 + } + } + }, + { + "__struct_id": 76, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Disease.", + "id": 88375 + } + } + }, + { + "__struct_id": 77, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Curse.", + "id": 88376 + } + } + }, + { + "__struct_id": 78, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Blindness/Deafness.", + "id": 88377 + } + } + }, + { + "__struct_id": 79, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Regenerate.", + "id": 88378 + } + } + }, + { + "__struct_id": 80, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Spells.", + "id": 88379 + } + } + }, + { + "__struct_id": 81, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Evil." + } + } + }, + { + "__struct_id": 82, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Elements.", + "id": 88380 + } + } + }, + { + "__struct_id": 83, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Premonition.", + "id": 88381 + } + } + }, + { + "__struct_id": 84, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Prayer.", + "id": 88382 + } + } + }, + { + "__struct_id": 85, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Owl's Wisdom.", + "id": 88383 + } + } + }, + { + "__struct_id": 86, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Neutralize poison.", + "id": 88384 + } + } + }, + { + "__struct_id": 87, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Monstrous Regeneration.", + "id": 88385 + } + } + }, + { + "__struct_id": 88, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minor Globe of Invulnerability.", + "id": 88386 + } + } + }, + { + "__struct_id": 89, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mind Blank.", + "id": 88387 + } + } + }, + { + "__struct_id": 90, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mass Haste.", + "id": 88388 + } + } + }, + { + "__struct_id": 91, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Magical Vestment.", + "id": 88389 + } + } + }, + { + "__struct_id": 92, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mage Armor.", + "id": 88390 + } + } + }, + { + "__struct_id": 93, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Light.", + "id": 88391 + } + } + }, + { + "__struct_id": 94, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Spell Mantle.", + "id": 88392 + } + } + }, + { + "__struct_id": 95, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Restoration.", + "id": 88393 + } + } + }, + { + "__struct_id": 96, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Mind Blank", + "id": 88394 + } + } + }, + { + "__struct_id": 97, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Dispel.", + "id": 88395 + } + } + }, + { + "__struct_id": 98, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Knock.", + "id": 88396 + } + } + }, + { + "__struct_id": 99, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility Sphere.", + "id": 88397 + } + } + }, + { + "__struct_id": 100, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility", + "id": 88398 + } + } + }, + { + "__struct_id": 101, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Improved Invisibility.", + "id": 88399 + } + } + }, + { + "__struct_id": 102, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Haste.", + "id": 88400 + } + } + }, + { + "__struct_id": 103, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Stoneskin.", + "id": 88401 + } + } + }, + { + "__struct_id": 104, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Spell Mantle.", + "id": 88402 + } + } + }, + { + "__struct_id": 105, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Sanctuary.", + "id": 88403 + } + } + }, + { + "__struct_id": 106, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Restoration.", + "id": 88404 + } + } + }, + { + "__struct_id": 107, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Magic Weapon.", + "id": 88405 + } + } + }, + { + "__struct_id": 108, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Dispelling.", + "id": 88406 + } + } + }, + { + "__struct_id": 109, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Globe of Invulnerability.", + "id": 88407 + } + } + }, + { + "__struct_id": 110, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ghostly Visage.", + "id": 88408 + } + } + }, + { + "__struct_id": 111, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Freedom of Movement.", + "id": 88409 + } + } + }, + { + "__struct_id": 112, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fox's Cunning", + "id": 88410 + } + } + }, + { + "__struct_id": 113, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Find Traps.", + "id": 88411 + } + } + }, + { + "__struct_id": 114, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ethereal Visage.", + "id": 88412 + } + } + }, + { + "__struct_id": 115, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Entropic Shield.", + "id": 88413 + } + } + }, + { + "__struct_id": 116, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Energy Buffer.", + "id": 88414 + } + } + }, + { + "__struct_id": 117, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I've changed my mind.", + "id": 88415 + } + } + }, + { + "__struct_id": 118, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 119, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endure Elements.", + "id": 88417 + } + } + }, + { + "__struct_id": 120, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endurance.", + "id": 88418 + } + } + }, + { + "__struct_id": 121, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Elemental Shield.", + "id": 88419 + } + } + }, + { + "__struct_id": 122, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Eagle's Splendour.", + "id": 88420 + } + } + }, + { + "__struct_id": 123, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Power.", + "id": 88421 + } + } + }, + { + "__struct_id": 124, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dispel Magic.", + "id": 88422 + } + } + }, + { + "__struct_id": 125, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Ward.", + "id": 88423 + } + } + }, + { + "__struct_id": 126, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Armor.", + "id": 88424 + } + } + }, + { + "__struct_id": 127, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Continual Flame.", + "id": 88426 + } + } + }, + { + "__struct_id": 128, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Clarity.", + "id": 88427 + } + } + }, + { + "__struct_id": 129, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cat's Grace.", + "id": 88428 + } + } + }, + { + "__struct_id": 130, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bull's Strength.", + "id": 88429 + } + } + }, + { + "__struct_id": 131, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 132, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 133, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 134, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 135, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 136, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 137, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 138, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 139, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bless.", + "id": 88445 + } + } + }, + { + "__struct_id": 140, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Aid.", + "id": 88447 + } + } + }, + { + "__struct_id": 141, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a healing spell." + } + } + }, + { + "__struct_id": 142, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Heal up the whole party.", + "id": 88431 + } + } + }, + { + "__struct_id": 143, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 144, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 145, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 146, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 147, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 148, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 149, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 150, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 151, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to discuss your tactics." + } + } + }, + { + "__struct_id": 152, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about something else." + } + } + }, + { + "__struct_id": 153, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Object" + } + } + ] + }, "Index": { "type": "dword", "value": 32 @@ -5686,12 +19633,28 @@ "Text": { "type": "cexolocstring", "value": { - "0": "I want you to behave differently when we face danger." + "0": "Lets discuss how you deal with objects." } } }, { - "__struct_id": 23, + "__struct_id": 154, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Bash" + } + } + ] + }, "Animation": { "type": "dword", "value": 0 @@ -5715,7 +19678,479 @@ "__struct_id": 0, "Active": { "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Object" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your bashing tactics.", + "id": 96501 + } + } + }, + { + "__struct_id": 155, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Locks" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Object" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your lock picking tactics.", + "id": 96501 + } + } + }, + { + "__struct_id": 156, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Traps" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Object" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your trap tactics.", + "id": 96502 + } + } + }, + { + "__struct_id": 157, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Search" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your search tactics." + } + } + }, + { + "__struct_id": 158, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Stealth" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your stealth tactics." + } + } + }, + { + "__struct_id": 159, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] }, "Index": { "type": "dword", @@ -5743,12 +20178,28 @@ "Text": { "type": "cexolocstring", "value": { - "0": "I want you to fight for me to the death!" + "0": "Let's change how you use magic in combat." } } }, { - "__struct_id": 24, + "__struct_id": 160, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicItems" + } + } + ] + }, "Animation": { "type": "dword", "value": 0 @@ -5772,7 +20223,951 @@ "__struct_id": 0, "Active": { "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you use magic items or not.", + "id": 96498 + } + } + }, + { + "__struct_id": 161, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Dispel" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your dispel tactics.", + "id": 96500 + } + } + }, + { + "__struct_id": 162, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stop countering the enemies spells.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 163, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 164, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BuffFirst" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change who you cast defensive spells on first.", + "id": 96500 + } + } + }, + { + "__struct_id": 165, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "OffensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast offensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 166, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast defensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 167, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "NoMagic" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change how you use magic spells in combat.", + "id": 96498 + } + } + }, + { + "__struct_id": 168, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic more in combat." + } + } + }, + { + "__struct_id": 169, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic less in combat." + } + } + }, + { + "__struct_id": 170, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] }, "Index": { "type": "dword", @@ -5800,12 +21195,593 @@ "Text": { "type": "cexolocstring", "value": { - "0": "Be brave! I want you fighting at my side at all times, unless you're badly hurt!" + "0": "Lets change when you decide to heal me.", + "id": 54985 } } }, { - "__struct_id": 25, + "__struct_id": 171, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal out of combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 172, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health an one needs for you to heal out of combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 173, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal during combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 174, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health any one needs for you to heal during combat.", + "id": 54991 + } + } + }, + { + "__struct_id": 175, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealSelf" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal yourself.", + "id": 54991 + } + } + }, + { + "__struct_id": 176, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealAllies" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal any allies.", + "id": 54991 + } + } + }, + { + "__struct_id": 177, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Pickup" + } + } + ] + }, "Animation": { "type": "dword", "value": 0 @@ -5829,7 +21805,292 @@ "__struct_id": 0, "Active": { "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change if you retrieve items and gold." + } + } + }, + { + "__struct_id": 178, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowFarther" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow farther away from me.", + "id": 96508 + } + } + }, + { + "__struct_id": 179, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowCloser" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow closer to me.", + "id": 96508 + } + } + }, + { + "__struct_id": 180, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] }, "Index": { "type": "dword", @@ -5857,12 +22118,28 @@ "Text": { "type": "cexolocstring", "value": { - "0": "Try not to get into trouble. Avoid tough foes." + "0": "Lets talk about your tactics in combat." } } }, { - "__struct_id": 26, + "__struct_id": 181, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AttackTactics" + } + } + ] + }, "Animation": { "type": "dword", "value": 0 @@ -5886,7 +22163,1046 @@ "__struct_id": 0, "Active": { "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you fight every opponent during combat." + } + } + }, + { + "__struct_id": 182, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AtkAssociates" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your tactics against familiars, companions, and summons.", + "id": 62531 + } + } + }, + { + "__struct_id": 183, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Ranged" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your ranged combat tactics.", + "id": 62531 + } + } + }, + { + "__struct_id": 184, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 185, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Taunt" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to taunt the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 186, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "PeaceTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Don't engage in combat.", + "2": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"", + "3": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"" + } + } + }, + { + "__struct_id": 187, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RangedTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use agressive ranged tactics, stay out of melee.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 188, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AmbushTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use ambush tactics, hide and then strike.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 189, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use defensive tactics protect yourself.", + "id": 62532 + } + } + }, + { + "__struct_id": 190, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use basic combat tactics.", + "id": 62531 + } + } + }, + { + "__struct_id": 191, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x1_hen_identify" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you identify my equipment?", + "id": 88341 + } + } + }, + { + "__struct_id": 192, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Scout" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I would like you to scout the area." + } + } + }, + { + "__struct_id": 193, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] }, "Index": { "type": "dword", @@ -5911,519 +23227,6 @@ "type": "resref", "value": "" }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I don't want you to get hurt, my friend. Try to avoid all but the easiest combat." - } - } - }, - { - "__struct_id": 27, - "Animation": { - "type": "dword", - "value": 0 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 37 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "Trust your instincts when enemies approach us. I want you to be comfortable." - } - } - }, - { - "__struct_id": 28, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 38 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_srch_off" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "I don't need you to search anymore.", - "id": 58483 - } - } - }, - { - "__struct_id": 29, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 39 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_srch_on" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58483 - } - } - }, - { - "__struct_id": 30, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 40 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_stlth_off" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "0": "You can return to sight now.", - "id": 58485 - } - } - }, - { - "__struct_id": 31, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 41 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_stlth_on" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58485 - } - } - }, - { - "__struct_id": 32, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 42 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_18" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58487 - } - } - }, - { - "__struct_id": 33, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 43 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "nw_ch_dist_6" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": { - "id": 58489 - } - } - }, - { - "__struct_id": 34, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 44 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, - "Text": { - "type": "cexolocstring", - "value": {} - } - }, - { - "__struct_id": 35, - "Animation": { - "type": "dword", - "value": 1 - }, - "AnimLoop": { - "type": "byte", - "value": 1 - }, - "Comment": { - "type": "cexostring", - "value": "" - }, - "Delay": { - "type": "dword", - "value": 4294967295 - }, - "EntriesList": { - "type": "list", - "value": [ - { - "__struct_id": 0, - "Active": { - "type": "resref", - "value": "" - }, - "Index": { - "type": "dword", - "value": 47 - }, - "IsChild": { - "type": "byte", - "value": 0 - } - } - ] - }, - "Quest": { - "type": "cexostring", - "value": "" - }, - "Script": { - "type": "resref", - "value": "" - }, - "Sound": { - "type": "resref", - "value": "" - }, "Text": { "type": "cexolocstring", "value": { @@ -6432,7 +23235,11 @@ } }, { - "__struct_id": 36, + "__struct_id": 194, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -6458,9 +23265,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 48 + "value": 37 }, "IsChild": { "type": "byte", @@ -6487,7 +23298,11 @@ } }, { - "__struct_id": 37, + "__struct_id": 195, + "ActionParams": { + "type": "list", + "value": [] + }, "Animation": { "type": "dword", "value": 1 @@ -6513,9 +23328,13 @@ "type": "resref", "value": "" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 49 + "value": 38 }, "IsChild": { "type": "byte", @@ -6552,38 +23371,36 @@ "type": "resref", "value": "nw_ch_fm_st_01" }, + "ConditionParams": { + "type": "list", + "value": [] + }, "Index": { "type": "dword", - "value": 52 + "value": 39 } }, { "__struct_id": 1, "Active": { "type": "resref", - "value": "nw_ch_fm_st_03" + "value": "0c_if_ass_convo" }, - "Index": { - "type": "dword", - "value": 51 - } - }, - { - "__struct_id": 2, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_04" - }, - "Index": { - "type": "dword", - "value": 50 - } - }, - { - "__struct_id": 3, - "Active": { - "type": "resref", - "value": "nw_ch_fm_st_02" + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] }, "Index": { "type": "dword", diff --git a/src/module/dlg/oc_ai_henchmen.dlg.json b/src/module/dlg/oc_ai_henchmen.dlg.json new file mode 100644 index 0000000..d9ca1b6 --- /dev/null +++ b/src/module/dlg/oc_ai_henchmen.dlg.json @@ -0,0 +1,27180 @@ +{ + "__data_type": "DLG ", + "DelayEntry": { + "type": "dword", + "value": 0 + }, + "DelayReply": { + "type": "dword", + "value": 0 + }, + "EndConverAbort": { + "type": "resref", + "value": "" + }, + "EndConversation": { + "type": "resref", + "value": "" + }, + "EntryList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 38 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_scout" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 247 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_identify" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 246 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_open_inven" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 242 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 191 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 109 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 77 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_class" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nClass1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nClass2" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 2, + "Key": { + "type": "cexostring", + "value": "nClass3" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 3, + "Key": { + "type": "cexostring", + "value": "nClass4" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 4, + "Key": { + "type": "cexostring", + "value": "nClass5" + }, + "Value": { + "type": "cexostring", + "value": "10" + } + }, + { + "__struct_id": 5, + "Key": { + "type": "cexostring", + "value": "nClass6" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + }, + { + "__struct_id": 6, + "Key": { + "type": "cexostring", + "value": "nClass7" + }, + "Value": { + "type": "cexostring", + "value": "48" + } + }, + { + "__struct_id": 7, + "Key": { + "type": "cexostring", + "value": "nClass8" + }, + "Value": { + "type": "cexostring", + "value": "46" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 62 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 6 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 5 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_hen_leave" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 2 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_convo" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 1 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What would you like to discuss?" + } + } + }, + { + "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 4 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 3 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Are you sure you want to do that?" + } + } + }, + { + "__struct_id": 2, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_polymorph" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 61 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "305" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 55 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "304" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 50 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "898" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 44 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "900" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 40 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "901" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 36 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "903" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 32 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "902" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 28 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "1060" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "1061" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "257" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "sTarget" + }, + "Value": { + "type": "cexostring", + "value": "OBJECT_SELF" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "x2_d2_haslayon" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "x2_d1_dmight" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "x2_d1_dshield" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 7 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let's see what I can do...", + "id": 95904 + } + } + }, + { + "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 17 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 16 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 15 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 14 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 13 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 12 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 11 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And who should be the target of my healing?", + "id": 87722 + } + } + }, + { + "__struct_id": 4, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 21 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 31 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 30 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 29 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 35 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 34 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 33 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 39 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 38 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 37 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 9, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 43 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 42 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 41 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 49 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_feat" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 48 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 47 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 46 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 45 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 11, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 54 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 53 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 52 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 51 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 60 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 59 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 58 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 57 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 56 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Which form should I take?" + } + } + }, + { + "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 76 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_assoc" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 75 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x2_hen_tomishad3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 74 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 73 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 72 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 71 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 70 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 69 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 68 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 67 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 66 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 65 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 64 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 63 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What would you have me summon?" + } + } + }, + { + "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 108 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 98 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 88 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 78 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What would you like to discuss about my defensive spells?", + "id": 88866 + } + } + }, + { + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 87 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 86 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 85 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 84 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 83 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 82 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 81 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 80 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 79 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 97 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 96 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 95 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 94 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 93 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 92 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 91 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 90 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 89 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 107 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 106 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 105 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 104 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 103 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 102 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 101 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 100 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 99 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "0c_listhenchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And what is my target?", + "id": 87722 + } + } + }, + { + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 190 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 189 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 180 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 179 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 178 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 177 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 176 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 175 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 174 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 173 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 172 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 171 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 12, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 170 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 13, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 169 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 14, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 166 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 15, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 165 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 16, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 164 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 17, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 163 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 18, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 162 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 19, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 161 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 20, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 160 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 21, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 159 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 22, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 158 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 23, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 157 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 24, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 156 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 25, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 155 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 26, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 154 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 27, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 153 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 28, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 152 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 29, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 151 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 30, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 150 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 31, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 149 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 32, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 148 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 33, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 147 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 34, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 146 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 35, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 145 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 36, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 144 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 37, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 143 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 38, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 142 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 39, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 141 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 40, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 140 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 41, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 139 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 42, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 138 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 43, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 137 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 44, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 136 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 45, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 135 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 46, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 134 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 47, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 133 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 48, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 132 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 49, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 131 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 50, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 130 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 51, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 129 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 52, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 128 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 53, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 127 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 54, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 126 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 55, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 125 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 56, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 124 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 57, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 123 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 58, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 122 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 59, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 121 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 60, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 120 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 61, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 119 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 62, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 118 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 63, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 117 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 64, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 116 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 65, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 115 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 66, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 114 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 67, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 113 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 68, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 112 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 69, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 111 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 70, + "Active": { + "type": "resref", + "value": "0c_if_has_spell" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell1" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 110 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 71, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 192 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "What you want me to cast?", + "id": 87720 + } + } + }, + { + "__struct_id": 19, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 168 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 167 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "You sure?", + "id": 87721 + } + } + }, + { + "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 188 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 187 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 186 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 185 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 184 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 183 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 182 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 181 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 192 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Okay. Who shoulds I cast it on?", + "id": 87722 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 201 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 200 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "x0_d2_hasfamil" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 199 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "x0_d2_hascompan" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 198 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "x2_d1_hashench1" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 197 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "x2_d1_hashench2" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 196 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "x2_d1_hashench3" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 195 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "x2_d1_hashench4" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 194 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 193 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 192 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "x2_d1_gentags" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "And who should be the target of my healing?", + "id": 87722 + } + } + }, + { + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 231 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 230 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 229 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_if_pickuploot" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 228 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 221 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 210 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 209 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 208 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 204 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What do you have in mind?" + } + } + }, + { + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_skillrank" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSkill" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nRank" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 207 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_skillrank" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSkill" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nRank" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 206 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 205 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " Should I do something else?" + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 220 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 219 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_if_a_magic_m" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nMode" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 218 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 217 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 216 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 215 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 214 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "0c_if_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_cntrspell" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 213 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 212 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 211 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " How would you like me to use magic in combat?" + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 227 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 226 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 225 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 224 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 223 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 222 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " When do you think I should heal our allies?", + "id": 55427 + } + } + }, + { + "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 241 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_defensive" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 240 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ambusher" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 239 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_ranged" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 238 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "0c_no_com_script" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAIScript" + }, + "Value": { + "type": "cexostring", + "value": "ai_a_peaceful" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 237 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 5, + "Active": { + "type": "resref", + "value": "0c_if_taunt" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 236 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 6, + "Active": { + "type": "resref", + "value": "0c_if_cntrspell" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 235 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 7, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 234 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 8, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 233 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 9, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 232 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 10, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 202 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 11, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": " What do you think is the best tactic?" + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 245 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 244 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 2, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 243 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 3, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 203 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + }, + { + "__struct_id": 4, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sure, what would you like me to do?" + } + } + }, + { + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 29 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "RepliesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 249 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 248 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Speaker": { + "type": "cexostring", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wel-met. I think we should work together, what do you say?" + } + } + } + ] + }, + "NumWords": { + "type": "dword", + "value": 1148 + }, + "PreventZoomIn": { + "type": "byte", + "value": 1 + }, + "ReplyList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "That will be all for now." + } + } + }, + { + "__struct_id": 1, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_get_convo" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let us talk about something completely different." + } + } + }, + { + "__struct_id": 2, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 1 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "We should part ways." + } + } + }, + { + "__struct_id": 3, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I like having you around." + } + } + }, + { + "__struct_id": 4, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_fire_henchmen" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes I'm sure, Perhapse we'll meet again." + } + } + }, + { + "__struct_id": 5, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Speaking" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change how much you speak.", + "id": 96511 + } + } + }, + { + "__struct_id": 6, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 2 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you use a special ability?", + "id": 96382 + } + } + }, + { + "__struct_id": 7, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_d2_dshield" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Shield.", + "id": 96383 + } + } + }, + { + "__struct_id": 8, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_d2_dmight" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Might.", + "id": 96384 + } + } + }, + { + "__struct_id": 9, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 3 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lay on Hands.", + "id": 96385 + } + } + }, + { + "__struct_id": 10, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I've changed my mind.", + "id": 88430 + } + } + }, + { + "__struct_id": 11, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 12, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 13, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 14, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 15, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 16, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 17, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 18, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 19, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nFeat" + }, + "Value": { + "type": "cexostring", + "value": "257" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_use_feat" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your bard song.", + "id": 88342 + } + } + }, + { + "__struct_id": 20, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 4 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your construction shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 21, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "740" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Iron Golem" + } + } + }, + { + "__struct_id": 22, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "739" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Demon Flesh Golem" + } + } + }, + { + "__struct_id": 23, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "738" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stone Golem" + } + } + }, + { + "__struct_id": 24, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 5 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your outsider shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 25, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "735" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Slaad" + } + } + }, + { + "__struct_id": 26, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "734" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Rakshasa" + } + } + }, + { + "__struct_id": 27, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "733" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Azer" + } + } + }, + { + "__struct_id": 28, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 6 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your humanoid shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 29, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "684" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Kobold Assasin" + } + } + }, + { + "__struct_id": 30, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "683" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lizard folk" + } + } + }, + { + "__struct_id": 31, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "682" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Drow" + } + } + }, + { + "__struct_id": 32, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 7 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape V.", + "id": 88342 + } + } + }, + { + "__struct_id": 33, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "691" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mindflayer" + } + } + }, + { + "__struct_id": 34, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "679" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Medusa" + } + } + }, + { + "__struct_id": 35, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "694" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dire Tiger" + } + } + }, + { + "__struct_id": 36, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 8 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape III.", + "id": 88342 + } + } + }, + { + "__struct_id": 37, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "674" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Manticore" + } + } + }, + { + "__struct_id": 38, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "673" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Drider" + } + } + }, + { + "__struct_id": 39, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "670" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Basilisk" + } + } + }, + { + "__struct_id": 40, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 9 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape II.", + "id": 88342 + } + } + }, + { + "__struct_id": 41, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "680" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minotaur" + } + } + }, + { + "__struct_id": 42, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "678" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Gargoyle" + } + } + }, + { + "__struct_id": 43, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "672" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Harpy" + } + } + }, + { + "__struct_id": 44, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 10 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your greater wild shape I.", + "id": 88342 + } + } + }, + { + "__struct_id": 45, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "662" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Green Wyrmling" + } + } + }, + { + "__struct_id": 46, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "661" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "White Wyrmling" + } + } + }, + { + "__struct_id": 47, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "660" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Black Wyrmling" + } + } + }, + { + "__struct_id": 48, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "659" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Blue Wyrmling" + } + } + }, + { + "__struct_id": 49, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "658" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Red Wyrmling" + } + } + }, + { + "__struct_id": 50, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 11 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your elemental shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 51, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "398" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Water" + } + } + }, + { + "__struct_id": 52, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "397" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fire" + } + } + }, + { + "__struct_id": 53, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "399" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Earth" + } + } + }, + { + "__struct_id": 54, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "400" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Air" + } + } + }, + { + "__struct_id": 55, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 12 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your wild shape.", + "id": 88342 + } + } + }, + { + "__struct_id": 56, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "405" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Badger" + } + } + }, + { + "__struct_id": 57, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "404" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Boar" + } + } + }, + { + "__struct_id": 58, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "403" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wolf" + } + } + }, + { + "__struct_id": 59, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "402" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Panther" + } + } + }, + { + "__struct_id": 60, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "401" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_cast_polymorp" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bear" + } + } + }, + { + "__struct_id": 61, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nEffectType" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_remove_effect" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Transform back into your natural form.", + "id": 96384 + } + } + }, + { + "__struct_id": 62, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 13 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to summon something if you can." + } + } + }, + { + "__struct_id": 63, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "178" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IX.", + "id": 88353 + } + } + }, + { + "__struct_id": 64, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "182" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VIII.", + "id": 88354 + } + } + }, + { + "__struct_id": 65, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "181" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VII.", + "id": 88355 + } + } + }, + { + "__struct_id": 66, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "180" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature VI.", + "id": 88356 + } + } + }, + { + "__struct_id": 67, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "179" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature V.", + "id": 88358 + } + } + }, + { + "__struct_id": 68, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "177" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature IV.", + "id": 88358 + } + } + }, + { + "__struct_id": 69, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "176" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature III.", + "id": 88359 + } + } + }, + { + "__struct_id": 70, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "175" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature II.", + "id": 88360 + } + } + }, + { + "__struct_id": 71, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "174" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Creature I.", + "id": 88361 + } + } + }, + { + "__struct_id": 72, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "30" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Create Undead.", + "id": 88425 + } + } + }, + { + "__struct_id": 73, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Animate Dead.", + "id": 88446 + } + } + }, + { + "__struct_id": 74, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x2_hen_tomishad4" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Summon Shadow." + } + } + }, + { + "__struct_id": 75, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Familiar" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Familiar." + } + } + }, + { + "__struct_id": 76, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAssociate" + }, + "Value": { + "type": "cexostring", + "value": "Companion" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_summon_assoc" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Your Companion." + } + } + }, + { + "__struct_id": 77, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 14 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let us talk about your defensive spells.", + "id": 89061 + } + } + }, + { + "__struct_id": 78, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 15 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your defensive spells.", + "id": 89063 + } + } + }, + { + "__struct_id": 79, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 80, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 81, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 82, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 83, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 84, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 85, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 86, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 87, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 88, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 16 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your long duration defensive spells.", + "id": 89064 + } + } + }, + { + "__struct_id": 89, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 90, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 91, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 92, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 93, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 94, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 95, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 96, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 97, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 98, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 17 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast all your short duration defensive spells.", + "id": 89065 + } + } + }, + { + "__struct_id": 99, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast on all the party members.", + "id": 88431 + } + } + }, + { + "__struct_id": 100, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 101, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 102, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 103, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 104, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 105, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 106, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 107, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 108, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "RestBuffing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 14 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast long duration spells after resting." + } + } + }, + { + "__struct_id": 109, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 18 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a spell.", + "id": 88348 + } + } + }, + { + "__struct_id": 110, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "441" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Wounding Whispers.", + "id": 88350 + } + } + }, + { + "__struct_id": 111, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "365" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ultravision.", + "id": 88351 + } + } + }, + { + "__struct_id": 112, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "186" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "True Seeing.", + "id": 88352 + } + } + }, + { + "__struct_id": 113, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "172" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stoneskin.", + "id": 88362 + } + } + }, + { + "__struct_id": 114, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "168" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Resistance.", + "id": 88363 + } + } + }, + { + "__struct_id": 115, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "169" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Spell Mantle.", + "id": 88364 + } + } + }, + { + "__struct_id": 116, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "450" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield of Faith.", + "id": 88365 + } + } + }, + { + "__struct_id": 117, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "417" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shield.", + "id": 88366 + } + } + }, + { + "__struct_id": 118, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "159" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Shadow Shield.", + "id": 88367 + } + } + }, + { + "__struct_id": 119, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "157" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "See Invisibility.", + "id": 88368 + } + } + }, + { + "__struct_id": 120, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "154" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Sanctuary.", + "id": 88369 + } + } + }, + { + "__struct_id": 121, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "152" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Restoration.", + "id": 88370 + } + } + }, + { + "__struct_id": 122, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "151" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resistance.", + "id": 88371 + } + } + }, + { + "__struct_id": 123, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "150" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Resist Elements.", + "id": 88372 + } + } + }, + { + "__struct_id": 124, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "149" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Paralysis.", + "id": 88373 + } + } + }, + { + "__struct_id": 125, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "148" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Fear.", + "id": 88374 + } + } + }, + { + "__struct_id": 126, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "147" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Disease.", + "id": 88375 + } + } + }, + { + "__struct_id": 127, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "146" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Curse.", + "id": 88376 + } + } + }, + { + "__struct_id": 128, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "145" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Remove Blindness/Deafness.", + "id": 88377 + } + } + }, + { + "__struct_id": 129, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "374" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Regenerate.", + "id": 88378 + } + } + }, + { + "__struct_id": 130, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "141" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Spells.", + "id": 88379 + } + } + }, + { + "__struct_id": 131, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "321" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Evil." + } + } + }, + { + "__struct_id": 132, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "137" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Protection From Elements.", + "id": 88380 + } + } + }, + { + "__struct_id": 133, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "134" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Premonition.", + "id": 88381 + } + } + }, + { + "__struct_id": 134, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "133" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Prayer.", + "id": 88382 + } + } + }, + { + "__struct_id": 135, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "355" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Owl's Wisdom.", + "id": 88383 + } + } + }, + { + "__struct_id": 136, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "126" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Neutralize poison.", + "id": 88384 + } + } + }, + { + "__struct_id": 137, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "525" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Monstrous Regeneration.", + "id": 88385 + } + } + }, + { + "__struct_id": 138, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "119" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Minor Globe of Invulnerability.", + "id": 88386 + } + } + }, + { + "__struct_id": 139, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "117" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mind Blank.", + "id": 88387 + } + } + }, + { + "__struct_id": 140, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "113" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mass Haste.", + "id": 88388 + } + } + }, + { + "__struct_id": 141, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "108" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Magical Vestment.", + "id": 88389 + } + } + }, + { + "__struct_id": 142, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "102" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Mage Armor.", + "id": 88390 + } + } + }, + { + "__struct_id": 143, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "100" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Light.", + "id": 88391 + } + } + }, + { + "__struct_id": 144, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "99" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Spell Mantle.", + "id": 88392 + } + } + }, + { + "__struct_id": 145, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "97" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Restoration.", + "id": 88393 + } + } + }, + { + "__struct_id": 146, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "95" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Mind Blank", + "id": 88394 + } + } + }, + { + "__struct_id": 147, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "94" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lesser Dispel.", + "id": 88395 + } + } + }, + { + "__struct_id": 148, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "93" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Knock.", + "id": 88396 + } + } + }, + { + "__struct_id": 149, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "92" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility Sphere.", + "id": 88397 + } + } + }, + { + "__struct_id": 150, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "90" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Invisibility", + "id": 88398 + } + } + }, + { + "__struct_id": 151, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "88" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Improved Invisibility.", + "id": 88399 + } + } + }, + { + "__struct_id": 152, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "78" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Haste.", + "id": 88400 + } + } + }, + { + "__struct_id": 153, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "74" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Stoneskin.", + "id": 88401 + } + } + }, + { + "__struct_id": 154, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "73" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Spell Mantle.", + "id": 88402 + } + } + }, + { + "__struct_id": 155, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "443" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Sanctuary.", + "id": 88403 + } + } + }, + { + "__struct_id": 156, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "70" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Restoration.", + "id": 88404 + } + } + }, + { + "__struct_id": 157, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "109" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Magic Weapon.", + "id": 88405 + } + } + }, + { + "__struct_id": 158, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "67" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Greater Dispelling.", + "id": 88406 + } + } + }, + { + "__struct_id": 159, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "65" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Globe of Invulnerability.", + "id": 88407 + } + } + }, + { + "__struct_id": 160, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "120" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ghostly Visage.", + "id": 88408 + } + } + }, + { + "__struct_id": 161, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "62" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Freedom of Movement.", + "id": 88409 + } + } + }, + { + "__struct_id": 162, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "356" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Fox's Cunning", + "id": 88410 + } + } + }, + { + "__struct_id": 163, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "377" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Find Traps.", + "id": 88411 + } + } + }, + { + "__struct_id": 164, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "121" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Ethereal Visage.", + "id": 88412 + } + } + }, + { + "__struct_id": 165, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "418" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Entropic Shield.", + "id": 88413 + } + } + }, + { + "__struct_id": 166, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "369" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Energy Buffer.", + "id": 88414 + } + } + }, + { + "__struct_id": 167, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "No, I've changed my mind.", + "id": 88415 + } + } + }, + { + "__struct_id": 168, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yes, go ahead.", + "id": 88416 + } + } + }, + { + "__struct_id": 169, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "50" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endure Elements.", + "id": 88417 + } + } + }, + { + "__struct_id": 170, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "49" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Endurance.", + "id": 88418 + } + } + }, + { + "__struct_id": 171, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "47" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Elemental Shield.", + "id": 88419 + } + } + }, + { + "__struct_id": 172, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "354" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Eagle's Splendour.", + "id": 88420 + } + } + }, + { + "__struct_id": 173, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "42" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Divine Power.", + "id": 88421 + } + } + }, + { + "__struct_id": 174, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "41" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Dispel Magic.", + "id": 88422 + } + } + }, + { + "__struct_id": 175, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "38" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Ward.", + "id": 88423 + } + } + }, + { + "__struct_id": 176, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "519" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 19 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Death Armor.", + "id": 88424 + } + } + }, + { + "__struct_id": 177, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "419" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Continual Flame.", + "id": 88426 + } + } + }, + { + "__struct_id": 178, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "21" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Clarity.", + "id": 88427 + } + } + }, + { + "__struct_id": 179, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "13" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cat's Grace.", + "id": 88428 + } + } + }, + { + "__struct_id": 180, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "9" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bull's Strength.", + "id": 88429 + } + } + }, + { + "__struct_id": 181, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 182, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 183, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 184, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 185, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 186, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 187, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 188, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 189, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Bless.", + "id": 88445 + } + } + }, + { + "__struct_id": 190, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nSpell" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 20 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_h_cast_spell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Aid.", + "id": 88447 + } + } + }, + { + "__struct_id": 191, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 21 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to cast a healing spell." + } + } + }, + { + "__struct_id": 192, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I've changed my mind.", + "id": 88430 + } + } + }, + { + "__struct_id": 193, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "0" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Heal up the whole party.", + "id": 88431 + } + } + }, + { + "__struct_id": 194, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "6" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88437 + } + } + }, + { + "__struct_id": 195, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "5" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88438 + } + } + }, + { + "__struct_id": 196, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88439 + } + } + }, + { + "__struct_id": 197, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "3" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on .", + "id": 88440 + } + } + }, + { + "__struct_id": 198, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "8" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my animal companion.", + "id": 88441 + } + } + }, + { + "__struct_id": 199, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "7" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on my familiar.", + "id": 88442 + } + } + }, + { + "__struct_id": 200, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "1" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on me.", + "id": 88443 + } + } + }, + { + "__struct_id": 201, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "nTarget" + }, + "Value": { + "type": "cexostring", + "value": "2" + } + }, + { + "__struct_id": 1, + "Key": { + "type": "cexostring", + "value": "nBuffType" + }, + "Value": { + "type": "cexostring", + "value": "4" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_henchmenspell" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Cast it on yourself.", + "id": 88444 + } + } + }, + { + "__struct_id": 202, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to discuss how we can work together." + } + } + }, + { + "__struct_id": 203, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about something else." + } + } + }, + { + "__struct_id": 204, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets discuss how you deal with objects." + } + } + }, + { + "__struct_id": 205, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Bash" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your bashing tactics.", + "id": 96507 + } + } + }, + { + "__struct_id": 206, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Locks" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your lock picking tactics.", + "id": 96507 + } + } + }, + { + "__struct_id": 207, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Traps" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Objects" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 23 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your trap tactics.", + "id": 96502 + } + } + }, + { + "__struct_id": 208, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Search" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your search tactics.", + "id": 96505 + } + } + }, + { + "__struct_id": 209, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Stealth" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I need you to change your stealth tactics.", + "id": 96505 + } + } + }, + { + "__struct_id": 210, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Let's change how you use magic in combat." + } + } + }, + { + "__struct_id": 211, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you use magic items or not.", + "id": 96498 + } + } + }, + { + "__struct_id": 212, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Dispel" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your dispel tactics.", + "id": 96500 + } + } + }, + { + "__struct_id": 213, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Stop countering the enemies spells.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 214, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Counter the enemy spells!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 215, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BuffFirst" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change who you cast defensive spells on first.", + "id": 96500 + } + } + }, + { + "__struct_id": 216, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "OffensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast offensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 217, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveCasting" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you cast defensive spells.", + "id": 96498 + } + } + }, + { + "__struct_id": 218, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "NMagic" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change how you use magic spells in combat.", + "id": 96498 + } + } + }, + { + "__struct_id": 219, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic more in combat." + } + } + }, + { + "__struct_id": 220, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "MagicMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Spells" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 24 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your magic less in combat." + } + } + }, + { + "__struct_id": 221, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change when you should heal.", + "id": 54985 + } + } + }, + { + "__struct_id": 222, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal out of combat.", + "id": 54990 + } + } + }, + { + "__struct_id": 223, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealOutMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health an one needs for you to heal out of combat.", + "id": 54989 + } + } + }, + { + "__struct_id": 224, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInPlus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Increase the health an one needs for you to heal during combat.", + "id": 54990 + } + } + }, + { + "__struct_id": 225, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealInMinus" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Reduce the health any one needs for you to heal during combat.", + "id": 54989 + } + } + }, + { + "__struct_id": 226, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealSelf" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal yourself.", + "id": 54989 + } + } + }, + { + "__struct_id": 227, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "HealAllies" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Healing" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 25 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you heal any allies.", + "id": 54989 + } + } + }, + { + "__struct_id": 228, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Pickup" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets change if you pickup items and gold." + } + } + }, + { + "__struct_id": 229, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowFarther" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow farther away from me.", + "id": 96510 + } + } + }, + { + "__struct_id": 230, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "FollowCloser" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "Plans" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 22 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Follow closer to me.", + "id": 96511 + } + } + }, + { + "__struct_id": 231, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Lets talk about your tactics in combat." + } + } + }, + { + "__struct_id": 232, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AttackTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change if you fight every opponent during combat.", + "2": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"", + "3": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"" + } + } + }, + { + "__struct_id": 233, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AtkAssociates" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your tactics against familiars, companions, and summons.", + "id": 62531 + } + } + }, + { + "__struct_id": 234, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Ranged" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Change your ranged combat tactics.", + "id": 62531 + } + } + }, + { + "__struct_id": 235, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "CounterSpell" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to counter spell the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 236, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Taunt" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want you to taunt the enemy!", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 237, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "PeaceTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Don't engage in combat.", + "2": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"", + "3": "\"Je ne veux pas du tout que vous vous engagiez dans un combat à distance rapproché,eloignez vous de l'enemi s'il devient trop proche!\"" + } + } + }, + { + "__struct_id": 238, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "RangedTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use agressive ranged tactics, stay out of melee.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 239, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "AmbushTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use ambush tactics, hide and then strike.", + "2": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"", + "3": "\"Je veux que vous fassiez confiance à votre instinct du moment où il faut changer entre armes de mélée ou à projectiles.\"" + } + } + }, + { + "__struct_id": 240, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "DefensiveTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use defensive tactics to protect yourself.", + "id": 62532 + } + } + }, + { + "__struct_id": 241, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "BasicTactics" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 1 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "CombatTactics" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 26 + }, + "IsChild": { + "type": "byte", + "value": 1 + }, + "LinkComment": { + "type": "cexostring", + "value": "" + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Use your best judgement in combat.", + "id": 62531 + } + } + }, + { + "__struct_id": 242, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 27 + }, + "IsChild": { + "type": "byte", + "value": 0 + } + } + ] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can we talk about your items?" + } + } + }, + { + "__struct_id": 243, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "GiveMagicItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Give me all the magical items in your inventory.", + "id": 96514 + } + } + }, + { + "__struct_id": 244, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "GiveUnIdentifiedItems" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Give me all your unidentified items.", + "id": 96514 + } + } + }, + { + "__struct_id": 245, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "x0_d1_hen_inven" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I want to adjust your equipment.", + "id": 96514 + } + } + }, + { + "__struct_id": 246, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Identify" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Can you identify our equipment?", + "id": 88341 + } + } + }, + { + "__struct_id": 247, + "ActionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sAction" + }, + "Value": { + "type": "cexostring", + "value": "Scout" + } + } + ] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_assoc_actions" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "I would like you to scout the area." + } + } + }, + { + "__struct_id": 248, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 0 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Not right now." + } + } + }, + { + "__struct_id": 249, + "ActionParams": { + "type": "list", + "value": [] + }, + "Animation": { + "type": "dword", + "value": 45 + }, + "AnimLoop": { + "type": "byte", + "value": 1 + }, + "Comment": { + "type": "cexostring", + "value": "" + }, + "Delay": { + "type": "dword", + "value": 4294967295 + }, + "EntriesList": { + "type": "list", + "value": [] + }, + "Quest": { + "type": "cexostring", + "value": "" + }, + "Script": { + "type": "resref", + "value": "0c_get_henchman" + }, + "Sound": { + "type": "resref", + "value": "" + }, + "Text": { + "type": "cexolocstring", + "value": { + "0": "Yea, thats a good idea." + } + } + } + ] + }, + "StartingList": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Active": { + "type": "resref", + "value": "0c_if_not_master" + }, + "ConditionParams": { + "type": "list", + "value": [] + }, + "Index": { + "type": "dword", + "value": 28 + } + }, + { + "__struct_id": 1, + "Active": { + "type": "resref", + "value": "0c_if_ass_convo" + }, + "ConditionParams": { + "type": "list", + "value": [ + { + "__struct_id": 0, + "Key": { + "type": "cexostring", + "value": "sOption" + }, + "Value": { + "type": "cexostring", + "value": "BaseMode" + } + } + ] + }, + "Index": { + "type": "dword", + "value": 0 + } + } + ] + } +} diff --git a/src/module/ifo/module.ifo.json b/src/module/ifo/module.ifo.json index 1c24ff2..f3a53f5 100644 --- a/src/module/ifo/module.ifo.json +++ b/src/module/ifo/module.ifo.json @@ -788,7 +788,7 @@ "Mod_Description": { "type": "cexolocstring", "value": { - "0": "The Lord of Terror - The Diablo Campaign [PRC8-CEP3]\n\nThis is a remake of the original Diablo game published by Blizzard Entertainment, along with its expansion, Hellfire, published by Sierra Online. This reimagining of the Diablo saga features all the original quests, plus additional story-related side quests that will further enhance the engrossing story of the Diablo saga.\n\nThis module was created by Tolitz Rosel. \n\nRequires PRC 8, CEP 1 & CEP 3 (for visuals)\n\nFor game hints and walkthrough, visit http://nwn.tolitz.com/lordofterror/" + "0": "The Lord of Terror - The Diablo Campaign [PRC8-CEP3]\n\nNOW WITH PEPS AI!\n\nThis is a remake of the original Diablo game published by Blizzard Entertainment, along with its expansion, Hellfire, published by Sierra Online. This reimagining of the Diablo saga features all the original quests, plus additional story-related side quests that will further enhance the engrossing story of the Diablo saga.\n\nThis module was created by Tolitz Rosel. \n\nRequires PRC 8, CEP 1 & CEP 3 (for visuals)\n\nFor game hints and walkthrough, visit http://nwn.tolitz.com/lordofterror/" } }, "Mod_DuskHour": { @@ -830,6 +830,13 @@ "Mod_HakList": { "type": "list", "value": [ + { + "__struct_id": 8, + "Mod_Hak": { + "type": "cexostring", + "value": "peps_prc8" + } + }, { "__struct_id": 8, "Mod_Hak": { @@ -1077,7 +1084,7 @@ }, "Mod_OnClientEntr": { "type": "resref", - "value": "prc_onenter" + "value": "hif_onenter" }, "Mod_OnClientLeav": { "type": "resref", diff --git a/src/module/itp/creaturepalcus.itp.json b/src/module/itp/creaturepalcus.itp.json index 9909c2c..b117f20 100644 --- a/src/module/itp/creaturepalcus.itp.json +++ b/src/module/itp/creaturepalcus.itp.json @@ -19955,7 +19955,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 0.5 + "value": 0.3333 }, "FACTION": { "type": "cexostring", diff --git a/src/module/nss/0c_assoc_actions.nss b/src/module/nss/0c_assoc_actions.nss new file mode 100644 index 0000000..74975d4 --- /dev/null +++ b/src/module/nss/0c_assoc_actions.nss @@ -0,0 +1,172 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_assoc_actions + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Conversation script that sets modes or allows oAssociate to do actions from a + conversation. + Param "sAction" +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oPC = GetPCSpeaker(); + object oAssociate = OBJECT_SELF; + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + object oArea = GetArea(oAssociate); + string sAction = GetScriptParam("sAction"); + // Scout ahead is done int 0e_ch_1_hb (heartbeat script). + if(sAction == "Scout") + { + ai_ClearCreatureActions(); + ai_HaveCreatureSpeak(oAssociate, 4, ":29:35:46:"); + ai_SetAIMode(oAssociate, AI_MODE_SCOUT_AHEAD, TRUE); + ai_ScoutAhead(oAssociate); + } + else if(sAction == "BasicTactics") + { + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, ""); + ai_SetAssociateAIScript(oAssociate, FALSE); + } + else if(sAction == "AmbushTactics") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_ambusher"); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, "ai_a_ambusher"); + } + else if(sAction == "DefensiveTactics") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_defensive"); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, "ai_a_defensive"); + } + else if(sAction == "RangedTactics") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_ranged"); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, "ai_a_ranged"); + } + else if(sAction == "Taunt") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_taunter"); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, "ai_a_taunter"); + } + else if(sAction == "CounterSpell") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_cntrspell"); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, "ai_a_cntrspell"); + } + else if(sAction == "PeaceTactics") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, "ai_a_peaceful"); + } + else if(sAction == "AttackTactics") + { + if(ai_GetAIMode(oAssociate, AI_MODE_CHECK_ATTACK)) + { + ai_SetAIMode(oAssociate, AI_MODE_CHECK_ATTACK, FALSE); + } + else ai_SetAIMode(oAssociate, AI_MODE_CHECK_ATTACK, TRUE); + } + else if(sAction == "FollowCloser") ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sAction == "FollowFarther") ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sAction == "Pickup") ai_Loot(oPC, oAssociate, sAssociateType); + else if(sAction == "HealSelf") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 1); + else if(sAction == "HealAllies") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 2); + else if(sAction == "HealOutMinus") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sAction == "HealOutPlus") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sAction == "HealInMinus") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sAction == "HealInPlus") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sAction == "Traps") ai_Traps(oPC, oAssociate, sAssociateType); + else if(sAction == "Locks") ai_Locks(oPC, oAssociate, sAssociateType, 1); + else if(sAction == "Bash") ai_Locks(oPC, oAssociate, sAssociateType, 2); + else if(sAction == "Search") ai_Search(oPC, oAssociate, sAssociateType); + else if(sAction == "Stealth") ai_Stealth(oPC, oAssociate, sAssociateType); + else if(sAction == "NoMagic") ai_UseMagic(oPC, oAssociate, sAssociateType); + else if(sAction == "DefensiveCasting") ai_UseOffensiveMagic(oPC, oAssociate, TRUE, FALSE, sAssociateType); + else if(sAction == "OffensiveCasting") ai_UseOffensiveMagic(oPC, oAssociate, FALSE, TRUE, sAssociateType); + else if(sAction == "MagicMinus") ai_MagicIncrement(oPC, oAssociate, -1, sAssociateType); + else if(sAction == "MagicPlus") ai_MagicIncrement(oPC, oAssociate, 1, sAssociateType); + else if(sAction == "Speaking") + { + if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK)) + { + ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, FALSE); + } + else ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, TRUE); + } + else if(sAction == "Ranged") + { + if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED)) + { + ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, FALSE); + } + else ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, TRUE); + } + else if(sAction == "AtkAssociates") + { + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES)) + { + ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, FALSE); + } + else ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, TRUE); + } + else if(sAction == "BuffFirst") + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_MASTER)) + { + ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_MASTER, FALSE); + } + else ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_MASTER, TRUE); + } + else if(sAction == "RestBuffing") + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST)) + { + ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST, FALSE); + } + else ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST, TRUE); + } + else if(sAction == "Dispel") + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_STOP_DISPEL)) + { + ai_SetMagicMode(oAssociate, AI_MAGIC_STOP_DISPEL, FALSE); + } + else ai_SetMagicMode(oAssociate, AI_MAGIC_STOP_DISPEL, TRUE); + } + else if(sAction == "MagicItems") + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS)) + { + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, FALSE); + } + else ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, TRUE); + } + else if(sAction == "Identify") + { + ai_IdentifyAllVsKnowledge(oAssociate, oPC, oPC); + return; + } + else if(sAction == "GiveUnIdentifiedItems") + { + ai_ClearCreatureActions(); + object oItem = GetFirstItemInInventory(oAssociate); + while(oItem != OBJECT_INVALID) + { + if(!GetIdentified(oItem)) ActionGiveItem(oItem, oPC); + oItem = GetNextItemInInventory(oAssociate); + } + return; + } + else if(sAction == "GiveMagicItems") + { + ai_ClearCreatureActions(); + itemproperty ipItemProp; + object oItem = GetFirstItemInInventory(oAssociate); + while(oItem != OBJECT_INVALID) + { + ipItemProp = GetFirstItemProperty(oItem); + if(GetIsItemPropertyValid(ipItemProp)) ActionGiveItem(oItem, oPC); + oItem = GetNextItemInInventory(oAssociate); + } + return; + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} diff --git a/src/module/nss/0c_cast_polymorp.nss b/src/module/nss/0c_cast_polymorp.nss new file mode 100644 index 0000000..b06f183 --- /dev/null +++ b/src/module/nss/0c_cast_polymorp.nss @@ -0,0 +1,18 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + Script Name: 0c_cast_polymorp + Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Conversation script to have a henchman cast a polymorph spell. + int nSpell is the spell to cast. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_items" +void main() +{ + object oHenchman = OBJECT_SELF; + int nSpell = StringToInt (GetScriptParam ("nSpell")); + // Save the original form so we can check when we turn back (Add 1 so we don't save a 0!). + SetLocalInt (oHenchman, AI_NORMAL_FORM, GetAppearanceType (oHenchman) + 1); + SetLocalString (oHenchman, AI_COMBAT_SCRIPT, "ai_a_polymorphed"); + ActionCastSpellAtObject (nSpell, oHenchman, 255, TRUE); +} + diff --git a/src/module/nss/0c_fire_henchmen.nss b/src/module/nss/0c_fire_henchmen.nss new file mode 100644 index 0000000..5505be9 --- /dev/null +++ b/src/module/nss/0c_fire_henchmen.nss @@ -0,0 +1,15 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_fire_henchmen + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Action taken script to fire/remove henchman for higher. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oHenchman = OBJECT_SELF; + ai_ClearCreatureActions(); + ai_FireHenchman (GetPCSpeaker(), oHenchman); + PlayVoiceChat (VOICE_CHAT_GOODBYE, oHenchman); +} + diff --git a/src/module/nss/0c_get_convo.nss b/src/module/nss/0c_get_convo.nss new file mode 100644 index 0000000..7cdfd40 --- /dev/null +++ b/src/module/nss/0c_get_convo.nss @@ -0,0 +1,22 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_get_convo + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Action taken script that leaves the current conversation and starts a new + conversation with oCreature using the linked conversation instead of the + ai_Henchman conversation. + + Allows use of ai_conversation for henchman in other modules. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void BeginOriginalHenchmanConversation(string sDialog, object oPC) +{ + BeginConversation(sDialog, oPC); +} +void main() +{ + ai_ClearCreatureActions(); + // Need to check special dialogs for HOTU henchman. + string sDialog = GetDialogFileToUse(GetLastSpeaker()); + DelayCommand(0.0, BeginOriginalHenchmanConversation(sDialog, GetPCSpeaker())); +} diff --git a/src/module/nss/0c_get_henchman.nss b/src/module/nss/0c_get_henchman.nss new file mode 100644 index 0000000..e0952d5 --- /dev/null +++ b/src/module/nss/0c_get_henchman.nss @@ -0,0 +1,25 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_get_henchman + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Action taken script that adds oCreature to oPC's party as a henchman + while giving a random message. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oPC = GetPCSpeaker(); + AddHenchman(oPC, oCreature); + int nVoice; + switch(d4()) + { + case 1: nVoice = VOICE_CHAT_CANDO; break; + case 2: nVoice = VOICE_CHAT_CHEER; break; + case 3: nVoice = VOICE_CHAT_GOODIDEA; break; + case 4: nVoice = VOICE_CHAT_LAUGH; break; + } + PlayVoiceChat(nVoice, oCreature); +} + + diff --git a/src/module/nss/0c_h_cast_spell.nss b/src/module/nss/0c_h_cast_spell.nss new file mode 100644 index 0000000..40868d8 --- /dev/null +++ b/src/module/nss/0c_h_cast_spell.nss @@ -0,0 +1,12 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_cast_spell + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Action taken script that sets the specified spell to be cast. + Param + nSpell - the spell to cast. +*/////////////////////////////////////////////////////////////////////////////// +void main() +{ + SetLocalInt (OBJECT_SELF, "0_SPELL_TO_CAST", StringToInt (GetScriptParam ("nSpell"))); +} diff --git a/src/module/nss/0c_henchmenspell.nss b/src/module/nss/0c_henchmenspell.nss new file mode 100644 index 0000000..5e64cba --- /dev/null +++ b/src/module/nss/0c_henchmenspell.nss @@ -0,0 +1,81 @@ +/*/////////////////////////////////////////////////////////////////////////////// + Script: 0c_henchmenspell + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Action script to cast a specific spell for a henchman. + + Script Param + nTarget (INT) : 0 = ALL, 1 PC, 2 Caster, 3-6 = oPC's Henchman, 7 = PC's Familiar + 8 = PC's Animal Companion, 9 = PC's Summon. + nBuffType = 1 all 2 short 3 long, 4 healing, 5 lay on hands. + If nBuffType is 0 then it will cast a specific spell from + Variable "0_SPELL_TO_CAST". Use script: 0c_h_spell_cast spell to set the spell. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +float ai_UseLayOnHands(object oTarget, object oPC, float fDelay, object oCaster); +void main() +{ + object oTarget, oPC = GetPCSpeaker(); + object oCreature = OBJECT_SELF; + float fDelay; + int nTarget = StringToInt(GetScriptParam("nTarget")); + int nBuffType = StringToInt(GetScriptParam("nBuffType")); + // Cast a group of buff spells based on nBuffType and nTarget or a single spell. + if(nBuffType < 4) + { + // Cast a specific spell. + if(nBuffType == 0) + { + int nSpell = GetLocalInt(oCreature, "0_SPELL_TO_CAST"); + // These are buff spells so Acid fog (index 0) is not a valid spell. + if(nSpell > 0) + { + ai_ClearCreatureActions(); + object oTarget = GetLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nTarget)); + if(oTarget != OBJECT_INVALID && ai_CheckAndCastSpell(oCreature, nSpell, 0, 0.0f, oTarget, oPC)) + { + DeleteLocalInt(oCreature, "0_SPELL_TO_CAST"); + } + else + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) PlayVoiceChat(VOICE_CHAT_CANTDO, oCreature); + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_SendMessages("I cannot cast " + sSpellName + ".", AI_COLOR_RED, oPC); + } + } + } + // Cast a creatures buff spells on nTarget. + else ai_CastBuffs(oCreature, nBuffType, nTarget, oPC); + } + // Cast Healing spells. + else if(nBuffType == 4) + { + ai_SetupAllyTargets(oCreature, oPC); + oTarget = GetLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nTarget)); + ai_TryHealing(oCreature, oTarget); + } + // Use lay on hands. + else if(nBuffType == 5) + { + ai_SetupAllyTargets(oCreature, oPC); + oTarget = GetLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nTarget)); + ai_UseLayOnHands(oTarget, oPC, 0.0f, oCreature); + } + else if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) PlayVoiceChat(VOICE_CHAT_CUSS, oCreature); +} +float ai_UseLayOnHands(object oTarget, object oPC, float fDelay, object oCreature) +{ + int nHpLost = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if(!nHpLost) + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) PlayVoiceChat(VOICE_CHAT_CANTDO, oCreature); + ai_SendMessages(GetName(oTarget) + " does not need healed.", AI_COLOR_RED, oPC); + } + else + { + ai_SendMessages(GetName(oCreature) + " is laying hands on " + GetName(oTarget), AI_COLOR_GREEN, oPC); + ActionUseFeat(FEAT_LAY_ON_HANDS, oTarget); + fDelay += 6.0f; + } + return fDelay; +} diff --git a/src/module/nss/0c_if_a_magic_m.nss b/src/module/nss/0c_if_a_magic_m.nss new file mode 100644 index 0000000..7ef4832 --- /dev/null +++ b/src/module/nss/0c_if_a_magic_m.nss @@ -0,0 +1,16 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_a_magic_m + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if the henchmen has a specific + associate magic mode. + Param: + nMode - The mode to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + int nMode = StringToInt(GetScriptParam("nMode")); + return ai_GetMagicMode (oHenchman, nMode); +} diff --git a/src/module/nss/0c_if_ass_convo.nss b/src/module/nss/0c_if_ass_convo.nss new file mode 100644 index 0000000..190a0f7 --- /dev/null +++ b/src/module/nss/0c_if_ass_convo.nss @@ -0,0 +1,132 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_ass_convo + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that has the henchman tell the player what options + have been selected. + + sOption will decide what the henchman says. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oPC = GetPCSpeaker(); + object oAssociate = OBJECT_SELF; + string sParam = GetScriptParam("sOption"); + if(sParam == "BaseMode") + { + string sBaseMode = "I'm ready to attack."; + string sVolume = " While shouting when I see things."; + // Lets get which base mode the henchman is in. + if(ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND)) sBaseMode = "I'm holding here."; + else if(ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER)) sBaseMode = "I'm defending you."; + else if(ai_GetAIMode(oAssociate, AI_MODE_FOLLOW)) sBaseMode = "I'm following you."; + if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_peaceful") sBaseMode = "I will not fight the enemy!"; + if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK)) sVolume = " While not speaking unless spoken to."; + SetCustomToken(AI_BASE_CUSTOM_TOKEN, sBaseMode + sVolume); + } + else if(sParam == "CombatTactics") + { + string sRangedUse = "", sCombatTactic = "I'm using my best judgement in combat "; + string sAtkAssociates = ""; + string sTargets = "against all enemies and "; + // Lets get which base mode the henchman is in. + if(ai_GetAIMode(oAssociate, AI_MODE_CHECK_ATTACK)) sTargets = "against enemies I can handle and "; + if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_ambusher") sCombatTactic = "I'm using ambush tactics "; + else if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_defensive") sCombatTactic = "I'm using defensive tactics "; + else if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_taunter") sCombatTactic = "I'm ready to taunt "; + else if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_cntrspell") sCombatTactic = "I'm ready to counter spell "; + if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_peaceful") + { + sCombatTactic = "I will not fight the enemy!"; + sTargets = ""; + } + else + { + if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED)) sRangedUse = "will not use a ranged weapon."; + else sRangedUse = "will use a ranged weapon."; + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES)) sAtkAssociates = " I will also ignore familiars, companions, and summons."; + else sAtkAssociates = " I will also attack familiars, companions, and summons."; + } + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 1, sCombatTactic + sTargets + sRangedUse + sAtkAssociates); + } + else if(sParam == "Plans") + { + float fFollowRange = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE); + string sFollowRange = FloatToString(fFollowRange, 0, 0); + string sDistance = "I'm following from " + sFollowRange + " meters away while"; + string sStealth, sSearch, sPickup; + if(ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS)) sPickup = " picking up items"; + else sPickup = " not picking up any items"; + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH)) sStealth = " in stealth"; + else sStealth = ""; + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH)) sSearch = " and searching"; + else sSearch = ""; + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 2, sDistance + sPickup + sStealth + sSearch + "."); + } + else if(sParam == "Healing") + { + string sHealingIn = IntToString(GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT)) + "%"; + string sHealingOut = IntToString(GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT)) + "%"; + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 5, "I'm healing our allies if they go below " + + sHealingIn + " health in combat and " + sHealingOut + " out of combat."); + } + else if(sParam == "Spells") + { + string sCastingLevel = "[" + IntToString(GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT)) + "] "; + string sCasting = "I'm casting"; + string sType = " spells I choose."; + string sBuff = " I'll also targeting anyone that needs it "; + string sDispel = "while using Dispel spells."; + string sMagicItems = " Lastly I'll use any magic items I have."; + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_MASTER)) sBuff = " Ofcourse I'll target you first "; + if(ai_GetMagicMode(oAssociate, AI_MAGIC_STOP_DISPEL)) sDispel = "while not using Dispel spells."; + if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_a_cntrspell") + { + sCasting = "I'm ready to counter spell our enemies."; + sType = ""; + sBuff = ""; + sDispel = ""; + } + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC)) + { + sCasting = "I'm not use any magic."; + sType = ""; + sBuff = ""; + sDispel = ""; + } + else if(ai_GetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING)) sType = " defensive spells only."; + else if(ai_GetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING)) + { + sType = " offensive spells only."; + sBuff = ""; + } + else if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS)) sMagicItems = " Finally I'll not use magic items."; + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 5, sCastingLevel + sCasting + sType + sBuff + sDispel+ sMagicItems); + } + else if(sParam == "Objects") + { + int bTraps = ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS); + int bLocks = ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS); + int bBash = ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS); + string sText = "I'm going to ignore all traps and locks."; + if(bTraps && bLocks && bBash) + { + sText = "I'm disarming all the traps and am either picking or bashing any of the locks we find."; + } + else if(bTraps && bLocks) sText = "I'm going to disarm all the traps and I'll pick all the locks we encounter."; + else if(bTraps && bBash) sText = "I shall disarm all the traps and will bash any locks we come across."; + else if(bTraps) sText = "I will disarm all the traps I can but will leave any locks for you to deal with."; + else if(bLocks && bBash) sText = "I will leave the traps for you but will either pick or bash any locks we see."; + else if(bLocks) sText = "I'll keep my distance from any traps we see, but will pick the locks found."; + else if(bBash) sText = "I'll let you mess with the traps, but I'll bash any locks that are out there."; + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 3, sText); + } + else if(sParam == "RestBuffing") + { + string sRestBuffing = ""; + if(!ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST)) sRestBuffing = "not "; + SetCustomToken(AI_BASE_CUSTOM_TOKEN + 10, "After we rest I am " + sRestBuffing + "casting my long buff spells on us."); + } + return TRUE; +} diff --git a/src/module/nss/0c_if_assoc_mode.nss b/src/module/nss/0c_if_assoc_mode.nss new file mode 100644 index 0000000..342bfff --- /dev/null +++ b/src/module/nss/0c_if_assoc_mode.nss @@ -0,0 +1,22 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_assoc_mode + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if the henchmen has a specific + associate mode. + Param: + nMode - The mode to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + int nMode = StringToInt(GetScriptParam("nMode")); + // This conversation line turns off picking up any items. + if (nMode == -1) + { + if(ai_SetAIMode (oHenchman, AI_MODE_PICKUP_ITEMS)) return TRUE; + return FALSE; + } + return ai_GetAIMode (oHenchman, nMode); +} diff --git a/src/module/nss/0c_if_cntrspell.nss b/src/module/nss/0c_if_cntrspell.nss new file mode 100644 index 0000000..a0a5c87 --- /dev/null +++ b/src/module/nss/0c_if_cntrspell.nss @@ -0,0 +1,17 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_cntrspell + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that returns TRUE the server allows a henchman to + use counterspell and if they don't have the counterspell ai script set. + Param: + sAIScript - The special combat script to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + return (AI_COUNTERSPELLING_ON && + ai_CheckClassType(oHenchman, AI_CLASS_TYPE_CASTER) && + GetLocalString(oHenchman, AI_COMBAT_SCRIPT) != "ai_a_cntrspell"); +} diff --git a/src/module/nss/0c_if_com_script.nss b/src/module/nss/0c_if_com_script.nss new file mode 100644 index 0000000..34d8370 --- /dev/null +++ b/src/module/nss/0c_if_com_script.nss @@ -0,0 +1,16 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_com_script + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that returns TRUE the caller does have an ai combat + script set to sAIScript. + Param: + sAIScript - The special combat script to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + string sAIScript = GetScriptParam("sAIScript"); + string sAICombatScript = GetLocalString (OBJECT_SELF, AI_COMBAT_SCRIPT); + return (sAIScript == sAICombatScript); +} diff --git a/src/module/nss/0c_if_convo.nss b/src/module/nss/0c_if_convo.nss new file mode 100644 index 0000000..83e1db4 --- /dev/null +++ b/src/module/nss/0c_if_convo.nss @@ -0,0 +1,21 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_if_convo + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that check if oCreature has a linked conversation. + Only checks for Henchman. + Allows use of ai_conversation for henchman in other modules. +*/////////////////////////////////////////////////////////////////////////////// +#include "nw_inc_gff" +#include "0i_messages" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + if(GetAssociateType(oHenchman) == ASSOCIATE_TYPE_HENCHMAN) + { + json jHenchman = ObjectToJson(oHenchman); + string sConversation = JsonGetString(GffGetResRef(jHenchman, "Conversation")); + if(sConversation != "") return TRUE; + } + return FALSE; +} diff --git a/src/module/nss/0c_if_has_assoc.nss b/src/module/nss/0c_if_has_assoc.nss new file mode 100644 index 0000000..cd16680 --- /dev/null +++ b/src/module/nss/0c_if_has_assoc.nss @@ -0,0 +1,18 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_has_assoc + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if caller has the specified feat + to summon either a companion or a familiar and they are not summoned. + Param + sAssociate - "Familiar" or "Companion" +*/////////////////////////////////////////////////////////////////////////////// +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + string sAssociate = GetScriptParam("sAssociate"); + if(sAssociate == "Familiar" && GetHasFeat(FEAT_SUMMON_FAMILIAR, oHenchman) && + GetAssociate(ASSOCIATE_TYPE_FAMILIAR) == OBJECT_INVALID) return TRUE; + return (sAssociate == "Companion" && GetHasFeat(FEAT_ANIMAL_COMPANION, oHenchman) && + GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION) == OBJECT_INVALID); +} diff --git a/src/module/nss/0c_if_has_class.nss b/src/module/nss/0c_if_has_class.nss new file mode 100644 index 0000000..1251c0a --- /dev/null +++ b/src/module/nss/0c_if_has_class.nss @@ -0,0 +1,28 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_has_class + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if conversation owner has a + specified class. Multiple classes maybe selected. + Param + nClass# - the class to look for use nClass1, nClass2, nClass3 for each one to check. +*/////////////////////////////////////////////////////////////////////////////// +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + int nCntr = 1; + int nClass; + string sClass; + while(nCntr < 10) + { + sClass = GetScriptParam("nClass" + IntToString(nCntr)); + if(sClass != "") + { + nClass = StringToInt(sClass); + if(GetLevelByClass(nClass, oHenchman)) return TRUE; + nCntr++; + } + else break; + } + return FALSE; +} diff --git a/src/module/nss/0c_if_has_feat.nss b/src/module/nss/0c_if_has_feat.nss new file mode 100644 index 0000000..fc111d8 --- /dev/null +++ b/src/module/nss/0c_if_has_feat.nss @@ -0,0 +1,22 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_has_feat + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if they have a specific feat. + Param: + sTarget - either "OBJECT_SELF", or "PCSpeaker", blanks defaults to "PCSpeaker" + nFeat - the feat number from Feats.2da + bNot - if 1 TRUE then this returns true for the target not having the feat. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +int StartingConditional() +{ + string sTarget = GetScriptParam("sTarget"); + int nFeat = StringToInt(GetScriptParam("nFeat")); + int bNot = StringToInt(GetScriptParam("bNot")); + object oCreature; + if(sTarget == "OBJECT_SELF") oCreature = OBJECT_SELF; + else if(sTarget == "" || sTarget == "PCSpeaker") oCreature = GetPCSpeaker(); + if(bNot) return !GetHasFeat(nFeat, oCreature); + return (GetHasFeat(nFeat ,oCreature) || ai_GetIsDungeonMaster(oCreature)); +} diff --git a/src/module/nss/0c_if_has_spell.nss b/src/module/nss/0c_if_has_spell.nss new file mode 100644 index 0000000..02004ff --- /dev/null +++ b/src/module/nss/0c_if_has_spell.nss @@ -0,0 +1,26 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_has_spell + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if caster can cast the specified spell. + Param + nSpell# - the spell to look for nSpell1, sSpell2, nSpell3 for each spell to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_spells" +int StartingConditional() +{ + object oCaster = OBJECT_SELF; + int nCnt = 1; + int nSpell; + string sSpell; + while(nCnt < 20) + { + sSpell = GetScriptParam("nSpell" + IntToString(nCnt)); + if(sSpell == "") return FALSE; + nSpell = StringToInt(sSpell); + if(GetHasSpell(nSpell, oCaster)) return TRUE; + //else if(ai_GetKnownSpell(oCaster, nSpell)) return TRUE; + nCnt++; + } + return FALSE; +} diff --git a/src/module/nss/0c_if_hen_leave.nss b/src/module/nss/0c_if_hen_leave.nss new file mode 100644 index 0000000..e2b2bbd --- /dev/null +++ b/src/module/nss/0c_if_hen_leave.nss @@ -0,0 +1,12 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_hen_leave + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that check if allowing the player to remove a henchman + is activated on this server. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + return AI_REMOVE_HENCHMAN_ON; +} diff --git a/src/module/nss/0c_if_identify.nss b/src/module/nss/0c_if_identify.nss new file mode 100644 index 0000000..b593baf --- /dev/null +++ b/src/module/nss/0c_if_identify.nss @@ -0,0 +1,17 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_identify + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if the henchmen has a better lore + skill than the speaker. + Also checks AI_IDENTIFY_ON to see if the server wants them to help. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + if (!AI_IDENTIFY_ON && !ai_CanISpeak (oHenchman)) return FALSE; + int nHenchmanLore = GetSkillRank(SKILL_LORE, oHenchman); + int nMasterLore = GetSkillRank(SKILL_LORE, GetMaster(oHenchman)); + return (nHenchmanLore > nMasterLore); +} diff --git a/src/module/nss/0c_if_not_master.nss b/src/module/nss/0c_if_not_master.nss new file mode 100644 index 0000000..73cb84e --- /dev/null +++ b/src/module/nss/0c_if_not_master.nss @@ -0,0 +1,11 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_not_master + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks if the speaker is the master of this + henchman. +*/////////////////////////////////////////////////////////////////////////////// +int StartingConditional() +{ + return !GetIsObjectValid(GetMaster()); +} diff --git a/src/module/nss/0c_if_open_inven.nss b/src/module/nss/0c_if_open_inven.nss new file mode 100644 index 0000000..2755c99 --- /dev/null +++ b/src/module/nss/0c_if_open_inven.nss @@ -0,0 +1,13 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_open_equip + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks if opening a henchmans inventory + is activated on this server. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + if(GetAssociateType(OBJECT_SELF) != ASSOCIATE_TYPE_HENCHMAN) return FALSE; + return AI_OPEN_INVENTORY; +} diff --git a/src/module/nss/0c_if_pickuploot.nss b/src/module/nss/0c_if_pickuploot.nss new file mode 100644 index 0000000..f4edfdb --- /dev/null +++ b/src/module/nss/0c_if_pickuploot.nss @@ -0,0 +1,12 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_pickuploot + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that check if having associates picking up loot is + activated on this server. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + return AI_PICKUP_LOOT; +} diff --git a/src/module/nss/0c_if_polymorph.nss b/src/module/nss/0c_if_polymorph.nss new file mode 100644 index 0000000..e2317f6 --- /dev/null +++ b/src/module/nss/0c_if_polymorph.nss @@ -0,0 +1,11 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_polymorph +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if the caller is polymorphed. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + if (GetLocalInt(OBJECT_SELF, AI_NORMAL_FORM) != 0) return TRUE; + return FALSE; +} diff --git a/src/module/nss/0c_if_scout.nss b/src/module/nss/0c_if_scout.nss new file mode 100644 index 0000000..9f7b0a3 --- /dev/null +++ b/src/module/nss/0c_if_scout.nss @@ -0,0 +1,11 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_scout + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that check if scouting is activated on this server. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + return AI_SCOUT_AHEAD_ON; +} diff --git a/src/module/nss/0c_if_skillrank.nss b/src/module/nss/0c_if_skillrank.nss new file mode 100644 index 0000000..e0d7729 --- /dev/null +++ b/src/module/nss/0c_if_skillrank.nss @@ -0,0 +1,18 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_SkillRank + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that checks to see if the caller's skill ranks + are above or equal to the param value. + Param: + nSkill - the skill number for the skill. See skills.2da. + nRank - the rank required. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +int StartingConditional() +{ + string sSkill = GetScriptParam("nSkill"); + if(sSkill == "") return FALSE; + int nRank = StringToInt(GetScriptParam("nRank")); + return (GetSkillRank(StringToInt(sSkill)) >= nRank); +} diff --git a/src/module/nss/0c_if_taunt.nss b/src/module/nss/0c_if_taunt.nss new file mode 100644 index 0000000..3e0fde6 --- /dev/null +++ b/src/module/nss/0c_if_taunt.nss @@ -0,0 +1,15 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_if_taunt + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that returns TRUE the server allows a henchman to + taunt and if they have the don't have the taunt ai script set. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + object oHenchman = OBJECT_SELF; + return (AI_TAUNTING_ON && + GetSkillRank(SKILL_TAUNT, oHenchman) > ai_GetCharacterLevels(oHenchman) && + GetLocalString(oHenchman, AI_COMBAT_SCRIPT) != "ai_a_taunter"); +} diff --git a/src/module/nss/0c_listhenchman.nss b/src/module/nss/0c_listhenchman.nss new file mode 100644 index 0000000..802f100 --- /dev/null +++ b/src/module/nss/0c_listhenchman.nss @@ -0,0 +1,19 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + Script Name: 0c_cast_polymorp + Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Conversation script to setup the tokens for the henchman in the speakers party + except for who they are talking to. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +void main() +{ + object oSpeaker = OBJECT_SELF; + object oPC = GetPCSpeaker(); + int nCntr = 1; + object oHenchman = GetHenchman(oPC, nCntr); + while(oHenchman != OBJECT_INVALID) + { + if(oHenchman != oSpeaker) SetCustomToken(77100 + nCntr, GetName(oHenchman)); + oHenchman = GetHenchman(oPC, ++nCntr); + } +} diff --git a/src/module/nss/0c_no_com_script.nss b/src/module/nss/0c_no_com_script.nss new file mode 100644 index 0000000..ca5c386 --- /dev/null +++ b/src/module/nss/0c_no_com_script.nss @@ -0,0 +1,27 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0c_no_com_script + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Text Appears When script that returns TRUE the caller does not have an ai combat + script set to sAIScript. + if sAIScript is blank then if its equal to all of them. + Param: sAIScripts:"ai_a_ambusher", "ai_a_defensive", "ai_a_taunter", "ai_coward". + sAIScript - The special combat script to check. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +int StartingConditional() +{ + string sAIScript = GetScriptParam("sAIScript"); + string sAICombatScript = GetLocalString (OBJECT_SELF, AI_COMBAT_SCRIPT); + // This is the value for do your own thing in combat! + if (sAIScript == "") + { + return (sAICombatScript == "ai_a_ambusher" || + sAICombatScript == "ai_a_defensive" || + sAICombatScript == "ai_a_ranged" || + sAICombatScript == "ai_a_taunter" || + sAICombatScript == "ai_a_cntrspell" || + sAICombatScript == "ai_a_peaceful"); + } + return (sAIScript != sAICombatScript); +} diff --git a/src/module/nss/0c_remove_effect.nss b/src/module/nss/0c_remove_effect.nss new file mode 100644 index 0000000..aa95a0c --- /dev/null +++ b/src/module/nss/0c_remove_effect.nss @@ -0,0 +1,14 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script:0c_remove_effect + Programmer:Philos +//////////////////////////////////////////////////////////////////////////////// + Actions Taken script that removes an effect from OBJECT_SELF. + Param: nEffect - the EFFECT_TYPE_* number to remove. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_spells" +void main () +{ + int nEffect = StringToInt (GetScriptParam ("nEffectType")); + ai_RemoveASpecificEffect (OBJECT_SELF, nEffect); +} + diff --git a/src/module/nss/0c_summon_assoc.nss b/src/module/nss/0c_summon_assoc.nss new file mode 100644 index 0000000..19544de --- /dev/null +++ b/src/module/nss/0c_summon_assoc.nss @@ -0,0 +1,17 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + Script Name: 0c_summon_assoc + Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Conversation script to have the caller summon either an animal companion or + familiar associate. + + Param + sAssociate - which associate to summon. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + string sAssociate = GetScriptParam ("sAssociate"); + if (sAssociate == "Familiar") SummonFamiliar (); + else if (sAssociate == "Companion") SummonAnimalCompanion (); +} diff --git a/src/module/nss/0c_use_feat.nss b/src/module/nss/0c_use_feat.nss new file mode 100644 index 0000000..ec3ddcc --- /dev/null +++ b/src/module/nss/0c_use_feat.nss @@ -0,0 +1,15 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + Script Name: 0c_summon_assoc + Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Conversation script to have the caller use nFeat from the feat.2da. + + Param + nFeat - Feat number from the feat.2da. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + int nFeat = StringToInt (GetScriptParam ("nFeat")); + ActionUseFeat(nFeat, OBJECT_SELF); +} diff --git a/src/module/nss/0e_c2_1_hb.nss b/src/module/nss/0e_c2_1_hb.nss new file mode 100644 index 0000000..05fbfc2 --- /dev/null +++ b/src/module/nss/0e_c2_1_hb.nss @@ -0,0 +1,16 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_c2_1_hb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnHeartbeat script; + This will usually fire every 6 seconds (1 game round). + + I am reverting the AI script back to the games default scripts for efficiency. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_module" +void main() +{ + SetLocalInt(OBJECT_SELF, AI_ONSPAWN_EVENT, TRUE); + ai_ChangeEventScriptsForMonster(OBJECT_SELF); + ExecuteScript("nw_c2_default1"); +} diff --git a/src/module/nss/0e_c2_7_ondeath.nss b/src/module/nss/0e_c2_7_ondeath.nss new file mode 100644 index 0000000..129e81e --- /dev/null +++ b/src/module/nss/0e_c2_7_ondeath.nss @@ -0,0 +1,32 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_c2_7_ondeath + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnDeath script; + This fires when the creature dies. +*//////////////////////////////////////////////////////////////////////////////// +#include "0i_module" +void main() +{ + object oCreature = OBJECT_SELF; + // Added code to allow for permanent associates in the battle! + object oModule = GetModule(); + if(GetLocalInt(oModule, AI_RULE_PERM_ASSOC)) + { + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex < 5; nIndex++) + { + oAssociate = GetAssociate(nIndex, oCreature); + if(oAssociate != OBJECT_INVALID) + { + SetIsDestroyable(FALSE, FALSE, FALSE); + DelayCommand(0.1, ChangeToStandardFaction(oAssociate, STANDARD_FACTION_HOSTILE)); + } + } + } + if(GetLocalInt(oModule, AI_RULE_CORPSES_STAY)) SetIsDestroyable(FALSE, FALSE, TRUE); + ai_ClearCombatState(oCreature); + ExecuteScript(GetLocalString(oCreature, "AI_ON_DEATH")); +} + diff --git a/src/module/nss/0e_ch_1_hb.nss b/src/module/nss/0e_ch_1_hb.nss new file mode 100644 index 0000000..d04eeb8 --- /dev/null +++ b/src/module/nss/0e_ch_1_hb.nss @@ -0,0 +1,14 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_ch_1_hb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate(Summons, Familiar, Companion) OnHeart beat script when out of combat; + This will usually fire every 6 seconds (1 game round). +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_module" +void main() +{ + SetLocalInt(OBJECT_SELF, AI_ONSPAWN_EVENT, TRUE); + ai_ChangeEventScriptsForAssociate(OBJECT_SELF); + ExecuteScript("nw_ch_ac1"); +} diff --git a/src/module/nss/0e_ch_7_ondeath.nss b/src/module/nss/0e_ch_7_ondeath.nss new file mode 100644 index 0000000..76d955d --- /dev/null +++ b/src/module/nss/0e_ch_7_ondeath.nss @@ -0,0 +1,41 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_ch_7_ondeath + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate OnSpawn script; + This fires when an associate dies. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_module" +void main() +{ + object oCreature = OBJECT_SELF; + // Added code to allow for permanent associates in the battle! + if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "13", GetName(oCreature) + " has died!" + + " AI_RULE_PERM_ASSOC: " + IntToString(GetLocalInt(GetModule(), AI_RULE_PERM_ASSOC))); + object oModule = GetModule(); + if(GetLocalInt(oModule, AI_RULE_PERM_ASSOC)) + { + object oAssociate; + int nIndex; + for(nIndex = 2; nIndex < 5; nIndex++) + { + oAssociate = GetAssociate(nIndex, oCreature); + if(oAssociate != OBJECT_INVALID) + { + SetIsDestroyable(FALSE, FALSE, FALSE); + ChangeFaction(oAssociate, oCreature); + } + } + } + // Remove the widget! + object oPC = GetMaster(oCreature); + if(oPC != OBJECT_INVALID) + { + NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oCreature) + AI_WIDGET_NUI)); + DelayCommand(0.5, ai_CheckXPPartyScale(oCreature)); + DelayCommand(2.0, ai_ClearCreatureActions(TRUE)); + } + DelayCommand(2.0, ai_ClearCombatState(oCreature)); + ExecuteScript(GetLocalString(oCreature, "AI_ON_DEATH")); +} + diff --git a/src/module/nss/0e_do_combat_rnd.nss b/src/module/nss/0e_do_combat_rnd.nss new file mode 100644 index 0000000..f1cb9c0 --- /dev/null +++ b/src/module/nss/0e_do_combat_rnd.nss @@ -0,0 +1,22 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_do_combat_rnd + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Used to execute a combat round just after the current action is over. + Note: Do not use with an attack action since it will continue until + the attacked enemy is dead. We end attack actions with a ClearAllActions + command and would also end this one so it will not work with attack actions. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("0e_do_combat_rnd", "14", GetName(oCreature) + " is calculating a new round." + + "nAction: " + IntToString(GetCurrentAction(oCreature))); + if(ai_GetIsInCombat(oCreature)) + { + if(GetAssociateType(oCreature) == ASSOCIATE_TYPE_NONE && + !ai_GetIsCharacter(oCreature)) ai_DoMonsterCombatRound(oCreature); + else if(ai_CanIAttack(oCreature)) ai_DoAssociateCombatRound(oCreature); + } +} diff --git a/src/module/nss/0e_gui_events.nss b/src/module/nss/0e_gui_events.nss new file mode 100644 index 0000000..401c825 --- /dev/null +++ b/src/module/nss/0e_gui_events.nss @@ -0,0 +1,60 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: 0e_gui_events + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + OnPlayerGUIEvent event script + Used to allow PEPS to gain control of specific GUI events. + +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_gui_events" +#include "0i_menus" +void main() +{ + object oPC = GetLastGuiEventPlayer(); + int nEventType = GetLastGuiEventType(); + int nEventInt = GetLastGuiEventInteger(); + //object oEventObject = GetLastGuiEventObject(); + switch(nEventType) + { + case GUIEVENT_EFFECTICON_CLICK: + { + if(ai_GetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT)) + { + ai_CreateEffectChatReport(oPC, nEventInt); + return; + } + int nToken = NuiFindWindow(oPC, AI_EFFECT_ICON_NUI); + json jData; + if(nToken) + { + jData = NuiGetUserData(oPC, nToken); + int nOldEffectIcon = JsonGetInt(JsonArrayGet(jData, 1)); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + if(nOldEffectIcon == nEventInt) return; + } + ai_CreateEffectIconMenu(oPC, nEventInt); + } + case GUIEVENT_PARTYBAR_PORTRAIT_CLICK: + { + object oAssociate = GetLastGuiEventObject(); + if(GetMaster(oAssociate) == oPC) + { + // If all the Command buttons are blocked then don't load the menu. + if(GetLocalInt(GetModule(), sDMWidgetAccessVarname) != 7340028) + { + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + if(IsWindowClosed(oPC, sAssociateType + AI_COMMAND_NUI)) + { + ai_CreateAssociateCommandNUI(oPC, oAssociate); + } + IsWindowClosed(oPC, sAssociateType + AI_NUI); + IsWindowClosed(oPC, sAssociateType + AI_LOOTFILTER_NUI); + IsWindowClosed(oPC, sAssociateType + AI_COPY_NUI); + IsWindowClosed(oPC, sAssociateType + AI_QUICK_WIDGET_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_MEMORIZE_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_KNOWN_NUI); + } + } + } + } +} diff --git a/src/module/nss/0e_m1_3_endround.nss b/src/module/nss/0e_m1_3_endround.nss new file mode 100644 index 0000000..e8a0125 --- /dev/null +++ b/src/module/nss/0e_m1_3_endround.nss @@ -0,0 +1,46 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_m1_3_endround + Original Script: m1_combanter_3 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnCombatRoundEnd event script used in the original campaign + for monsters that may do a one liner during combat; + + Fires at the end of each combat round (6 seconds). + This will fire as long as oCreature is in combat (GetIsInCombat()). + This event starts counting once a combat action is started. + Every time a spell is cast it will queue another end combat round so haste with + two spells cast will fire this twice in one round. + It will also fire at the end of a hostile effect that stops actions i.e Stunned, Knockdown etc. + Action modes are also cleared prior to this event executing! + GetAttemptedAttackTarget() & GetAttemptedSpellTarget() also get cleared prior to this event. + This event can be canceled with ClearAllActions(TRUE) and SurrenderToEnemies. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("0e_m1_3_endround", "23", GetName(oCreature) + " ends combat round."); + // Action modes get cleared prior to each OnCombatRoundEnd! + // We do this to keep the action mode going. + int nActionMode = GetLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + if(nActionMode > 0) + { + SetActionMode(oCreature, nActionMode, TRUE); + // We don't want to use up all of the Dwarven Defenders uses! + if(nActionMode == 12) IncrementRemainingFeatUses(oCreature, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE); + } + if (ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(Random(4) == 0) SpeakOneLinerConversation(); + if(ai_GetIsInCombat(oCreature)) ai_DoMonsterCombatRound(oCreature); + ai_SpellConcentrationCheck(oCreature); + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature); + if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1003)); + } +} + + + + diff --git a/src/module/nss/0e_nui.nss b/src/module/nss/0e_nui.nss new file mode 100644 index 0000000..7d18c65 --- /dev/null +++ b/src/module/nss/0e_nui.nss @@ -0,0 +1,1975 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: 0e_nui + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Menu event script + sEvent: close, click, mousedown, mouseup, watch (if bindwatch is set). +/*////////////////////////////////////////////////////////////////////////////// +#include "nw_inc_gff" +#include "x0_i0_assoc" +#include "0i_menus" +#include "0i_player_target" +// Save a window ID to the database. +void ai_SaveWindowLocation(object oPC, int nToken, string sAssociateType, string sWindowID); +// Sets the Widget Buttons state to sElem Checkbox state. +void ai_SetWidgetButtonToCheckbox(object oPC, int nButton, object oAssociate, string sAssociateType, int nToken, string sElem); +// Flips an AI Buttons state to sElem Checkbox state. +void ai_SetAIButtonToCheckbox(object oPC, int nButton, object oAssociate, string sAssociateType, int nToken, string sElem); +// Flips the flag for the loot filter to sElem Checkbox state. +void ai_SetLootFilterToCheckbox(object oPC, object oAssociate, int nFilterBit, int nToken, string sElem); +// Sets an associates companion type. Cannot set companion for a player! +void ai_SetCompanionType(object oPC, object oAssociate, int nToken, int nCompanionType); +// Sets an associates companion name. Cannot set companion for a player! +void ai_SetCompanionName(object oPC, object oAssociate, int nToken, int nCompanionType); +// Sets an associates AI script via a combo box. +void ai_SetAIScript(object oPC, object oAssociate, int nToken); +// Increments/Decrements the Perception Range use variable for the AI. +void ai_PercRangeIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType, int nToken); +// Saves an associates perception range changed on the button. +void ai_Perc_Range(object oPC, object oAssociate, int nToken, string sAssociateType); +// Changes Perception Distance Rule for monsters. +void ai_RulePercDistInc(object oPC, object oModule, int nIncrement, int nToken); +// Adds a spell to a json AI restricted spell list then returns jRules. +// bRestrict = TRUE will add to the list FALSE will remove it from the list. +json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE); +// Turns on oAssociate AI, Setting all event scripts. +void ai_TurnOn(object oPC, object oAssociate, string sAssociateType); +// Turns off oAssociate AI, Setting all event scripts. +void ai_TurnOff(object oPC, object oAssociate, string sAssociateType); +// Adds a henchman back into the players party. +object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion); + +void ai_SaveWindowLocation(object oPC, int nToken, string sAssociateType, string sWindowID) +{ + json jGeometry = NuiGetBind(oPC, nToken, "window_geometry"); + float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); + float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) jLocations = JsonObject(); + json jWindow = JsonObjectGet(jLocations, sWindowID); + if(JsonGetType(jWindow) == JSON_TYPE_NULL) jWindow = JsonObject(); + jWindow = JsonObjectSet(jWindow, "x", JsonFloat(fX)); + jWindow = JsonObjectSet(jWindow, "y", JsonFloat(fY)); + jLocations = JsonObjectSet(jLocations, sWindowID, jWindow); + //SendMessageToPC(oPC, "0e_nui, 52, sAssociateType: " + sAssociateType + + // " sWindowID: " + sWindowID + + // " jLocations: " + JsonDump(jLocations, 1)); + ai_SetAssociateDbJson(oPC, sAssociateType, "locations", jLocations); +} +void ai_ToggleAssociateWidgetOnOff(object oPC, int nToken, object oAssociate, string sAssociateType) +{ + string sText, sText2, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int bWidget = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType, bWidget); + NuiSetBind(oPC, nToken, "btn_widget_onoff", JsonBool (!bWidget)); + if(bWidget) + { + sText = "on"; + sText2 = "Off"; + IsWindowClosed(oPC, sAssociateType + AI_WIDGET_NUI); + } + else + { + sText = "off"; + sText2 = "On"; + ai_CreateWidgetNUI(oPC, oAssociate); + } + NuiSetBind(oPC, nToken, "btn_widget_onoff_label", JsonString("Widget " + sText2)); + NuiSetBind(oPC, nToken, "btn_widget_onoff_tooltip", JsonString(" Turn " + sName + " widget " + sText)); +} +void main() +{ + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + string sWndId = NuiGetWindowId(oPC, nToken); + //SendMessageToPC(oPC, "0e_nui , 64 sWndId: " + sWndId + " sEvent: " + sEvent + " sElem: " + sElem + + // " nToken: " + IntToString(nToken) + " nIndex: " + IntToString(nIndex) + + // " oPC: " + GetName(oPC)); + // Get if the menu has an associate attached. + json jData = NuiGetUserData(oPC, nToken); + object oAssociate = StringToObject(JsonGetString(JsonArrayGet(jData, 0))); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + if(!ai_GetIsCharacter(oAssociate) && !GetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE") && + (oAssociate == OBJECT_INVALID || GetMaster(oAssociate) != oPC)) + { + ai_SendMessages("This creature is no longer in your party!", AI_COLOR_RED, oPC); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + return; + } + if(sAssociateType == "") return; + //************************************************************************** + // Watch to see if the window moves and save. + if(sElem == "window_geometry" && sEvent == "watch") + { + if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + // If the widget is locked then don't save. + if(sWndId == sAssociateType + AI_WIDGET_NUI && + ai_GetWidgetButton(oPC, BTN_WIDGET_LOCK, oAssociate, sAssociateType)) return; + ai_SaveWindowLocation(oPC, nToken, sAssociateType, sWndId); + return; + } + //************************************************************************** + // Main AI events. + if(sWndId == AI_MAIN_NUI) + { + //if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + if(sEvent == "click") + { + if(sElem == "btn_plugin_manager") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreatePluginNUI(oPC); + } + else if(sElem == "btn_action_ghost") + { + // We set ghost mode differently for each AI. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + if(GetLocalInt(oPC, sGhostModeVarname)) + { + DeleteLocalInt(oPC, sGhostModeVarname); + ai_SendMessages("Action Ghost mode is turned off when using commands.", AI_COLOR_YELLOW, oPC); + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + } + else + { + SetLocalInt(oPC, sGhostModeVarname, TRUE); + ai_SendMessages("Action Ghost mode is turned on when using commands.", AI_COLOR_YELLOW, oPC); + } + } + else + { + if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST)) + { + ai_SetAIMode(oPC, AI_MODE_ACTION_GHOST, FALSE); + ai_SendMessages("Action Ghost mode is turned off when using commands.", AI_COLOR_YELLOW, oPC); + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID && !ai_GetAIMode(oAssociate, AI_MODE_GHOST)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID && !ai_GetAIMode(oAssociate, AI_MODE_GHOST)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + } + else + { + ai_SetAIMode(oPC, AI_MODE_ACTION_GHOST); + ai_SendMessages("Action Ghost mode is turned on when using commands.", AI_COLOR_YELLOW, oPC); + } + aiSaveAssociateModesToDb(oPC, oPC); + } + } + else if(sElem == "btn_toggle_assoc_widget") + { + int bWidgetOff = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc"); + string sAssocType; + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc", bWidgetOff); + object oAssoc = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff); + if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI); + else ai_CreateWidgetNUI(oPC, oAssoc); + } + oAssoc = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff); + if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI); + else ai_CreateWidgetNUI(oPC, oAssoc); + } + oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff); + if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI); + else ai_CreateWidgetNUI(oPC, oAssoc); + } + oAssoc = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff); + if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI); + else ai_CreateWidgetNUI(oPC, oAssoc); + } + int nIndex; + object oHenchman; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oHenchman != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oHenchman); + ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oHenchman, sAssocType, bWidgetOff); + if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI); + else ai_CreateWidgetNUI(oPC, oHenchman); + } + } + } + else if(sElem == "btn_effect_icon") + { + if(ai_GetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT)) + { + ai_SetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT, FALSE); + ai_SendMessages("All effect icons will be reported in a menu at the top of the screen.", AI_COLOR_YELLOW, oPC); + } + else + { + ai_SetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT); + ai_SendMessages("All effect icons will be reported in the chat screen.", AI_COLOR_YELLOW, oPC); + } + aiSaveAssociateModesToDb(oPC, oPC); + } + if(sElem == "btn_default_xp") + { + int nDefaultXP = GetLocalInt(GetModule(), AI_RULE_DEFAULT_XP_SCALE); + SetModuleXPScale(nDefaultXP); + NuiSetBind(oPC, nToken, "txt_xp_scale", JsonString(IntToString(nDefaultXP))); + } + } + if(sEvent == "watch") + { + string sPreElem = GetStringLeft(sElem, 4); + if(sPreElem == "txt_") + { + object oModule = GetModule(); + json jRules = ai_GetCampaignDbJson("rules"); + string sText = JsonGetString(NuiGetBind(oPC, nToken, sElem)); + if(sElem == "txt_max_henchman") + { + int nMaxHenchmen = StringToInt(sText); + if(nMaxHenchmen < 1) nMaxHenchmen = 1; + if(nMaxHenchmen > 12) + { + nMaxHenchmen = 12; + ai_SendMessages("The maximum henchmen for this mod is 12!", AI_COLOR_RED, oPC); + } + SetMaxHenchmen(nMaxHenchmen); + SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, nMaxHenchmen); + jRules = JsonObjectSet(jRules, AI_RULE_MAX_HENCHMAN, JsonInt(nMaxHenchmen)); + ai_SendMessages("Maximum henchmen has been changed to " + IntToString(nMaxHenchmen), AI_COLOR_YELLOW, oPC); + } + else if(sElem == "txt_ai_difficulty") + { + int nChance = StringToInt(sText); + if(nChance < 0) nChance = 0; + else if(nChance > 100) nChance = 100; + SetLocalInt(oModule, AI_RULE_AI_DIFFICULTY, nChance); + jRules = JsonObjectSet(jRules, AI_RULE_AI_DIFFICULTY, JsonInt(nChance)); + } + else if(sElem == "txt_perception_distance") + { + float fDistance = StringToFloat(sText); + if(fDistance < 10.0) fDistance = 10.0; + else if(fDistance > 60.0) fDistance = 60.0; + SetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE, fDistance); + jRules = JsonObjectSet(jRules, AI_RULE_PERCEPTION_DISTANCE, JsonFloat(fDistance)); + } + else if(sElem == "txt_inc_enc") + { + float fNumber = StringToFloat(sText); + if(fNumber < 0.0) fNumber = 0.0; + else if(fNumber > 9.0) fNumber = 9.0; + SetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS, fNumber); + jRules = JsonObjectSet(jRules, AI_INCREASE_ENC_MONSTERS, JsonFloat(fNumber)); + } + else if(sElem == "txt_inc_hp") + { + int nNumber = StringToInt(sText); + if(nNumber < 0) nNumber = 0; + else if(nNumber > 100) nNumber = 100; + SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, nNumber); + jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(nNumber)); + } + else if(sElem == "txt_wander_distance") + { + float fDistance = StringToFloat(sText); + if(fDistance < 0.0) fDistance = 0.0; + else if(fDistance > 99.0) fDistance = 99.0; + SetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE, fDistance); + jRules = JsonObjectSet(jRules, AI_RULE_WANDER_DISTANCE, JsonFloat(fDistance)); + } + else if(sElem == "txt_xp_scale") + { + int nNumber = StringToInt(sText); + if(nNumber < 0) nNumber = 0; + else if(nNumber > 200) nNumber = 200; + SetModuleXPScale(nNumber); + return; + } + ai_SetCampaignDbJson("rules", jRules); + } + else if(sPreElem == "chbx") + { + object oModule = GetModule(); + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + json jRules = ai_GetCampaignDbJson("rules"); + if(sElem == "chbx_moral_check") + { + SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_MORAL_CHECKS, JsonInt(bCheck)); + } + else if(sElem == "chbx_buff_monsters_check") + { + SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(bCheck)); + } + else if(sElem == "chbx_buff_summons_check") + { + SetLocalInt(oModule, AI_RULE_PRESUMMON, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PRESUMMON, JsonInt(bCheck)); + } + else if(sElem == "chbx_ambush_monsters_check") + { + SetLocalInt(oModule, AI_RULE_AMBUSH, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_AMBUSH, JsonInt(bCheck)); + } + else if(sElem == "chbx_companions_check") + { + SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_SUMMON_COMPANIONS, JsonInt(bCheck)); + } + else if(sElem == "chbx_advanced_movement_check") + { + SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ADVANCED_MOVEMENT, JsonInt(bCheck)); + } + else if(sElem == "chbx_ilr_check") + { + SetLocalInt(oModule, AI_RULE_ILR, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ILR, JsonInt(bCheck)); + } + else if(sElem == "chbx_umd_check") + { + SetLocalInt(oModule, AI_RULE_ALLOW_UMD, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ALLOW_UMD, JsonInt(bCheck)); + } + else if(sElem == "chbx_use_healingkits_check") + { + SetLocalInt(oModule, AI_RULE_HEALERSKITS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_HEALERSKITS, JsonInt(bCheck)); + } + else if(sElem == "chbx_perm_assoc_check") + { + SetLocalInt(oModule, AI_RULE_PERM_ASSOC, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PERM_ASSOC, JsonInt(bCheck)); + } + else if(sElem == "chbx_corpses_stay_check") + { + SetLocalInt(oModule, AI_RULE_CORPSES_STAY, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_CORPSES_STAY, JsonInt(bCheck)); + } + else if(sElem == "chbx_wander_check") + { + SetLocalInt(oModule, AI_RULE_WANDER, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_WANDER, JsonInt(bCheck)); + NuiSetBind(oPC, nToken, "txt_wander_distance_event", JsonBool(bCheck)); + } + else if(sElem == "chbx_open_doors_check") + { + SetLocalInt(oModule, AI_RULE_OPEN_DOORS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_OPEN_DOORS, JsonInt(bCheck)); + } + else if(sElem == "chbx_party_scale_check") + { + if(bCheck) + { + SetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP, GetModuleXPScale()); + ai_CheckXPPartyScale(oPC); + } + else + { + SetModuleXPScale(GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE)); + } + SetLocalInt(oModule, AI_RULE_PARTY_SCALE, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PARTY_SCALE, JsonInt(bCheck)); + string sText = IntToString(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP)); + NuiSetBind(oPC, nToken, "chbx_party_scale_tooltip", JsonString(" PEPS adjusts your XP based on party size from (" + sText + ").")); + sText = IntToString(GetModuleXPScale()); + NuiSetBind(oPC, nToken, "txt_xp_scale", JsonString(sText)); + } + else if(sElem == "chbx_darkness_check") + { + if(bCheck) + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_DARKNESS); + jRules = ai_AddRestrictedSpell(jRules, 159); + jRules = ai_AddRestrictedSpell(jRules, SPELLABILITY_AS_DARKNESS); + jRules = ai_AddRestrictedSpell(jRules, 688); // WildShape_Darkness + } + else + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_DARKNESS, FALSE); + jRules = ai_AddRestrictedSpell(jRules, 159, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELLABILITY_AS_DARKNESS, FALSE); + jRules = ai_AddRestrictedSpell(jRules, 688, FALSE); // WildShape_Darkness + } + } + else if(sElem == "chbx_dispels_check") + { + if(bCheck) + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_LESSER_DISPEL); + jRules = ai_AddRestrictedSpell(jRules, SPELL_DISPEL_MAGIC); + jRules = ai_AddRestrictedSpell(jRules, SPELL_GREATER_DISPELLING); + jRules = ai_AddRestrictedSpell(jRules, SPELL_MORDENKAINENS_DISJUNCTION); + } + else + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_LESSER_DISPEL, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_DISPEL_MAGIC, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_GREATER_DISPELLING, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_MORDENKAINENS_DISJUNCTION, FALSE); + } + } + else if(sElem == "chbx_timestop_check") + { + if(bCheck) jRules = ai_AddRestrictedSpell(jRules, SPELL_TIME_STOP); + else jRules = ai_AddRestrictedSpell(jRules, SPELL_TIME_STOP, FALSE); + } + ai_SetCampaignDbJson("rules", jRules); + } + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + // Follow range is only changed on non-pc's + if(sElem == "lbl_perc_dist") ai_RulePercDistInc(oPC, GetModule(), 1, nToken); + } + else if(nMouseScroll == -1.0) // Scroll down + { + // Follow range is only changed on non-pc's + if(sElem == "lbl_perc_dist") ai_RulePercDistInc(oPC, GetModule(), -1, nToken); + } + } + return; + } + //************************************************************************** + // Associate Command events. + if(sWndId == sAssociateType + AI_COMMAND_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_ai_menu") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreateAssociateAINUI(oPC, oAssociate); + } + if(sElem == "btn_vertical_widget") + { + int bVertical = !ai_GetWidgetButton(oPC, BTN_WIDGET_VERTICAL, oAssociate, sAssociateType); + ai_SetWidgetButton(oPC, BTN_WIDGET_VERTICAL, oAssociate, sAssociateType, bVertical); + if(oPC == oAssociate || + (oPC != oAssociate && !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType))) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + } + else if(sElem == "btn_main_menu") + { + if(ai_GetIsCharacter(oAssociate)) ai_CreateAIMainNUI(oPC); + } + else if(sElem == "btn_widget_onoff") + { + ai_ToggleAssociateWidgetOnOff(oPC, nToken, oAssociate, sAssociateType); + } + else if(sElem == "btn_widget_lock") + { + int bLocked = !ai_GetWidgetButton(oPC, BTN_WIDGET_LOCK, oAssociate, sAssociateType); + ai_SetWidgetButton(oPC, BTN_WIDGET_LOCK, oAssociate, sAssociateType, bLocked); + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + } + else if(sElem == "btn_copy_settings") + { + ai_CreateCopySettingsNUI(oPC, oAssociate); + } + else if(sElem == "btn_cmd_action") ai_Action(oPC, oAssociate); + else if(sElem == "btn_cmd_guard") ai_DoCommand(oPC, oAssociate, 1); + else if(sElem == "btn_cmd_hold") ai_DoCommand(oPC, oAssociate, 3); + else if(sElem == "btn_cmd_search") ai_DoCommand(oPC, oAssociate, 5); + else if(sElem == "btn_cmd_stealth") ai_DoCommand(oPC, oAssociate, 6); + else if(sElem == "btn_cmd_attack") ai_DoCommand(oPC, oAssociate, 4); + else if(sElem == "btn_cmd_follow") ai_DoCommand(oPC, oAssociate, 2); + else if(sElem == "btn_follow_target") ai_FollowTarget(oPC, oAssociate); + else if(sElem == "btn_cmd_ai_script") ai_AIScript(oPC, oAssociate, sAssociateType, nToken); + else if(sElem == "btn_cmd_place_trap") ai_HavePCPlaceTrap(oPC, oAssociate); + else if(sElem == "btn_quick_widget") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreateQuickWidgetSelectionNUI(oPC, oAssociate); + } + else if(sElem == "btn_spell_memorize") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreateSpellMemorizationNUI(oPC, oAssociate); + } + else if(sElem == "btn_spell_known") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreateSpellKnownNUI(oPC, oAssociate); + } + else if(sElem == "btn_buff_short") + { + ai_Buff_Button(oPC, oAssociate, 2, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_long") + { + ai_Buff_Button(oPC, oAssociate, 3, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_all") + { + ai_Buff_Button(oPC, oAssociate, 1, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_rest") ai_Buff_Button(oPC, oAssociate, 0, sAssociateType); + else if(sElem == "btn_jump_to") ai_JumpToPC(oPC, oAssociate); + else if(sElem == "btn_ghost_mode") ai_GhostMode(oPC, oAssociate, nToken, sAssociateType); + else if(sElem == "btn_camera") ai_ChangeCameraView(oPC, oAssociate); + else if(sElem == "btn_inventory") ai_OpenInventory(oAssociate, oPC); + else if(sElem == "btn_familiar_name") ai_SetCompanionName(oPC, oAssociate, nToken, ASSOCIATE_TYPE_FAMILIAR); + else if(sElem == "btn_companion_name") ai_SetCompanionName(oPC, oAssociate, nToken, ASSOCIATE_TYPE_ANIMALCOMPANION); + else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oPC, sElem); + } + else if(sEvent == "watch") + { + if(sElem == "txt_familiar_name") + { + string sName = JsonGetString(NuiGetBind(oPC, nToken, sElem)); + if(sName != "") NuiSetBind(oPC, nToken, "btn_familiar_name_event", JsonBool(TRUE)); + else NuiSetBind(oPC, nToken, "btn_familiar_name_event", JsonBool(FALSE)); + } + if(GetStringLeft(sElem, 12) == "chbx_plugin_" && GetStringRight(sElem, 6) == "_check") + { + int nIndex = StringToInt(GetSubString(sElem, 12, 1)); + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + json jPlugin = JsonArrayGet(jPlugins, nIndex); + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + else if(sElem == "chbx_buff_rest_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_BUFF_REST, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_action_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_ACTION, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_guard_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_GUARD, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_hold_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_HOLD, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_search_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_SEARCH, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_stealth_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_STEALTH, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_attack_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_ATTACK, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_follow_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_FOLLOW, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_ai_script_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_AI_SCRIPT, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cmd_place_trap_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_PLACE_TRAP, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_quick_widget_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_SPELL_WIDGET, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_follow_target_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_FOLLOW_TARGET, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_buff_short_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_BUFF_SHORT, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_buff_long_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_BUFF_LONG, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_buff_all_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_BUFF_ALL, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_jump_to_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_JUMP_TO, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_ghost_mode_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_GHOST_MODE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_camera_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_CAMERA, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_inventory_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_INVENTORY, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_familiar_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_FAMILIAR, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_companion_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_COMPANION, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "cmb_familiar_selected") ai_SetCompanionType(oPC, oAssociate, nToken, ASSOCIATE_TYPE_FAMILIAR); + else if(sElem == "cmb_companion_selected") ai_SetCompanionType(oPC, oAssociate, nToken, ASSOCIATE_TYPE_ANIMALCOMPANION); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + // Follow range is only changed on non-pc's + if(sElem == "btn_cmd_follow" && + oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType); + } + else if(nMouseScroll == -1.0) // Scroll down + { + // Follow range is only changed on non-pc's + if(sElem == "btn_cmd_follow" && + oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + } + } + return; + } + //************************************************************************** + // Associate AI events. + if(sWndId == sAssociateType + AI_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_command_menu") + { + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_CreateAssociateCommandNUI(oPC, oAssociate); + } + if(sElem == "btn_main_menu") + { + if(ai_GetIsCharacter(oAssociate)) ai_CreateAIMainNUI(oPC); + } + else if(sElem == "btn_loot_filter") + { + ai_CreateLootFilterNUI(oPC, oAssociate); + } + else if(sElem == "btn_ai") + { + if(GetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT) == "xx_pc_1_hb") ai_TurnOff(oPC, oAssociate, sAssociateType); + else ai_TurnOn(oPC, oAssociate, sAssociateType); + } + else if(sElem == "btn_quiet") ai_ReduceSpeech(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ranged") AssignCommand(oAssociate, ai_Ranged(oPC, oAssociate, sAssociateType)); + else if(sElem == "btn_equip_weapon") ai_EquipWeapons(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_search") ai_Search(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_stealth") ai_Stealth(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoor(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_traps") ai_Traps(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_pick_locks") ai_Locks(oPC, oAssociate, sAssociateType, 1); + else if(sElem == "btn_bash_locks") ai_Locks(oPC, oAssociate, sAssociateType, 2); + else if(sElem == "btn_magic") ai_UseMagic(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_magic_items") ai_UseMagicItems(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_def_magic") ai_UseOffensiveMagic(oPC, oAssociate, TRUE, FALSE, sAssociateType); + else if(sElem == "btn_off_magic") ai_UseOffensiveMagic(oPC, oAssociate, FALSE, TRUE, sAssociateType); + else if(sElem == "btn_spontaneous") ai_Spontaneous(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_heals_onoff") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 1); + else if(sElem == "btn_healp_onoff") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 2); + else if(sElem == "btn_cure_onoff") ai_Cure_OnOff(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_loot") ai_Loot(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ignore_assoc") ai_Ignore_Associates(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ignore_traps") ai_Ignore_Traps(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_perc_range") ai_Perc_Range(oPC, oAssociate, nToken, sAssociateType); + else if(sElem == "btn_ai_script") ai_SaveAIScript(oPC, oAssociate, nToken); + } + else if(sEvent == "watch") + { + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + if(sElem == "chbx_ai_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_FOR_PC, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_quiet_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_REDUCE_SPEECH, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_ranged_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_USE_RANGED, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_equip_weapon_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_STOP_WEAPON_EQUIP, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_search_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_USE_SEARCH, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_stealth_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_USE_STEALTH, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_open_door_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_OPEN_DOORS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_traps_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_REMOVE_TRAPS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_pick_locks_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_PICK_LOCKS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_bash_locks_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_BASH_LOCKS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_magic_level_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_MAGIC_LEVEL, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_spontaneous_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_NO_SPONTANEOUS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_magic_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_NO_MAGIC_USE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_magic_items_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_NO_MAGIC_ITEM_USE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_def_magic_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_DEF_MAGIC_USE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_off_magic_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_OFF_MAGIC_USE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_heal_out_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_HEAL_OUT, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_heal_in_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_HEAL_IN, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_heals_onoff_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_STOP_SELF_HEALING, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_healp_onoff_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_STOP_PARTY_HEALING, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_cure_onoff_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_STOP_CURE_SPELLS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_loot_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_LOOT, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_ignore_assoc_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_IGNORE_ASSOCIATES, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_ignore_traps_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_IGNORE_TRAPS, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "chbx_perc_range_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_PERC_RANGE, oAssociate, sAssociateType, nToken, sElem); + else if(sElem == "cmb_ai_script_selected") ai_SetAIScript(oPC, oAssociate, nToken); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + if(sElem == "btn_magic_level") ai_MagicIncrement(oPC, oAssociate, 1, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoorIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_traps") ai_TrapRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_pick_locks") ai_LockRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_bash_locks") ai_LockRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_heal_out") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, 1, sAssociateType, nToken); + } + else if(nMouseScroll == -1.0) // Scroll down + { + if(sElem == "btn_magic_level") ai_MagicIncrement(oPC, oAssociate, -1, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoorIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_traps") ai_TrapRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_pick_locks") ai_LockRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_bash_locks") ai_LockRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_heal_out") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, -1, sAssociateType, nToken); + } + } + return; + } + //************************************************************************** + // Associate Widget events. + if(sWndId == sAssociateType + AI_WIDGET_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_open_main") + { + // If all the Command buttons are blocked then don't load the menu. + if(GetLocalInt(GetModule(), sDMWidgetAccessVarname) != 7340028) + { + if(IsWindowClosed(oPC, sAssociateType + AI_COMMAND_NUI)) + { + ai_CreateAssociateCommandNUI(oPC, oAssociate); + } + IsWindowClosed(oPC, sAssociateType + AI_NUI); + IsWindowClosed(oPC, sAssociateType + AI_LOOTFILTER_NUI); + IsWindowClosed(oPC, sAssociateType + AI_COPY_NUI); + IsWindowClosed(oPC, sAssociateType + AI_QUICK_WIDGET_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_MEMORIZE_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_KNOWN_NUI); + if(ai_GetIsCharacter(oAssociate)) + { + IsWindowClosed(oPC, AI_MAIN_NUI); + IsWindowClosed(oPC, AI_PLUGIN_NUI); + } + } + } + else if(sElem == "btn_ai") + { + if(GetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT) == "xx_pc_1_hb") + { + ai_TurnOff(oPC, oAssociate, sAssociateType); + } + else ai_TurnOn(oPC, oAssociate, sAssociateType); + } + else if(sElem == "btn_quiet") ai_ReduceSpeech(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ranged") AssignCommand(oAssociate, ai_Ranged(oPC, oAssociate, sAssociateType)); + else if(sElem == "btn_equip_weapon") ai_EquipWeapons(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_search") ai_Search(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_stealth") ai_Stealth(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoor(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_traps") ai_Traps(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_pick_locks") ai_Locks(oPC, oAssociate, sAssociateType, 1); + else if(sElem == "btn_bash_locks") ai_Locks(oPC, oAssociate, sAssociateType, 2); + else if(sElem == "btn_magic_minus") ai_MagicIncrement(oPC, oAssociate, -1, sAssociateType); + else if(sElem == "btn_magic_plus") ai_MagicIncrement(oPC, oAssociate, 1, sAssociateType); + else if(sElem == "btn_magic") ai_UseMagic(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_magic_items") ai_UseMagicItems(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_def_magic") ai_UseOffensiveMagic(oPC, oAssociate, TRUE, FALSE, sAssociateType); + else if(sElem == "btn_off_magic") ai_UseOffensiveMagic(oPC, oAssociate, FALSE, TRUE, sAssociateType); + else if(sElem == "btn_cure_onoff") ai_Cure_OnOff(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_loot") ai_Loot(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ignore_assoc") ai_Ignore_Associates(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_ignore_traps") ai_Ignore_Traps(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_perc_range") ai_Perc_Range(oPC, oAssociate, nToken, sAssociateType); + else if(sElem == "btn_spontaneous") ai_Spontaneous(oPC, oAssociate, sAssociateType); + else if(sElem == "btn_buff_short") + { + ai_Buff_Button(oPC, oAssociate, 2, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_long") + { + ai_Buff_Button(oPC, oAssociate, 3, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_all") + { + ai_Buff_Button(oPC, oAssociate, 1, sAssociateType); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sElem == "btn_buff_rest") ai_Buff_Button(oPC, oAssociate, 0, sAssociateType); + else if(sElem == "btn_jump_to") ai_JumpToPC(oPC, oAssociate); + else if(sElem == "btn_ghost_mode") ai_GhostMode(oPC, oAssociate, nToken, sAssociateType); + else if(sElem == "btn_camera") ai_ChangeCameraView(oPC, oAssociate); + else if(sElem == "btn_inventory") ai_OpenInventory(oAssociate, oPC); + else if(sElem == "btn_familiar") + { + if(GetHasFeat(FEAT_SUMMON_FAMILIAR, oAssociate)) + { + DecrementRemainingFeatUses(oAssociate, FEAT_SUMMON_FAMILIAR); + SummonFamiliar(oAssociate); + } + } + else if(sElem == "btn_companion") + { + if(GetHasFeat(FEAT_ANIMAL_COMPANION, oAssociate)) + { + DecrementRemainingFeatUses(oAssociate, FEAT_ANIMAL_COMPANION); + SummonAnimalCompanion(oAssociate); + } + } + else if(sElem == "btn_heals_onoff") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 1); + else if(sElem == "btn_healp_onoff") ai_Heal_OnOff(oPC, oAssociate, sAssociateType, 2); + else if(sElem == "btn_cmd_action") ai_Action(oPC, oAssociate); + else if(sElem == "btn_cmd_guard") ai_DoCommand(oPC, oAssociate, 1); + else if(sElem == "btn_cmd_hold") ai_DoCommand(oPC, oAssociate, 3); + else if(sElem == "btn_cmd_search") ai_DoCommand(oPC, oAssociate, 5); + else if(sElem == "btn_cmd_stealth") ai_DoCommand(oPC, oAssociate, 6); + else if(sElem == "btn_cmd_attack") ai_DoCommand(oPC, oAssociate, 4); + else if(sElem == "btn_cmd_follow") ai_DoCommand(oPC, oAssociate, 2); + else if(sElem == "btn_cmd_ai_script") ai_AIScript(oPC, oAssociate, sAssociateType, nToken); + else if(sElem == "btn_cmd_place_trap") ai_HavePCPlaceTrap(oPC, oAssociate); + else if(sElem == "btn_follow_target") ai_FollowTarget(oPC, oAssociate); + else if(sElem == "btn_update_widget") ai_UpdateAssociateWidget(oPC, oAssociate); + else if(GetStringLeft(sElem, 15) == "btn_exe_plugin_") ai_Plugin_Execute(oPC, sElem); + else if(GetStringLeft(sElem, 11) == "btn_widget_") ai_SelectWidgetSpellTarget(oPC, oAssociate, sElem); + } + if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + if(sElem == "btn_cmd_follow" && + oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_magic_level") ai_MagicIncrement(oPC, oAssociate, 1, sAssociateType); + else if(sElem == "btn_pick_locks") ai_LockRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_bash_locks") ai_LockRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_traps") ai_TrapRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoorIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_heal_out") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, 1.0, sAssociateType); + else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, 1, sAssociateType, -1); + } + if(nMouseScroll == -1.0) // Scroll down + { + if(sElem == "btn_cmd_follow" && + oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_magic_plus") ai_MagicIncrement(oPC, oAssociate, -1, sAssociateType); + if(sElem == "btn_magic_level") ai_MagicIncrement(oPC, oAssociate, -1, sAssociateType); + else if(sElem == "btn_pick_locks") ai_LockRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_bash_locks") ai_LockRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_traps") ai_TrapRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_open_door") ai_OpenDoorIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_heal_out") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_OUT_OF_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType); + else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, -1, sAssociateType, -1); + } + } + if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + AssignCommand(oPC, PlaySound("gui_button")); + if(sElem == "btn_open_main") + { + // If all the AI buttons are blocked then don't load the menu. + if(GetLocalInt(GetModule(), sDMAIAccessVarname) != 203423743) + { + if(IsWindowClosed(oPC, sAssociateType + AI_NUI)) + { + ai_CreateAssociateAINUI(oPC, oAssociate); + } + } + IsWindowClosed(oPC, sAssociateType + AI_COMMAND_NUI); + IsWindowClosed(oPC, sAssociateType + AI_LOOTFILTER_NUI); + IsWindowClosed(oPC, sAssociateType + AI_COPY_NUI); + IsWindowClosed(oPC, sAssociateType + AI_QUICK_WIDGET_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_MEMORIZE_NUI); + IsWindowClosed(oPC, sAssociateType + AI_SPELL_KNOWN_NUI); + if(ai_GetIsCharacter(oAssociate)) + { + IsWindowClosed(oPC, AI_MAIN_NUI); + IsWindowClosed(oPC, AI_PLUGIN_NUI); + } + } + else if(sElem == "btn_follow_range") ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType); + else if(GetStringLeft(sElem, 11) == "btn_widget_") + { + if(GetStringLength(sElem) == 13) nIndex = StringToInt(GetStringRight(sElem, 2)); + else nIndex = StringToInt(GetStringRight(sElem, 1)); + json jAIData = ai_GetAssociateDbJson(oPC, ai_GetAssociateType(oPC, oAssociate), "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jSpell = JsonArrayGet(jWidget, nIndex); + ai_CreateDescriptionNUI(oPC, jSpell); + } + } + } + return; + } + //************************************************************************** + // Associate Loot events. + if(sWndId == sAssociateType + AI_LOOTFILTER_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_set_all") + { + SetLocalInt(oPC, "AI_BLOCK_CHECKS", TRUE); + SetLocalInt(oAssociate, sLootFilterVarname, 65535); + int nIndex; + for(nIndex = 2; nIndex < 20; nIndex++) + { + NuiSetBind(oPC, nToken, "chbx_" + IntToString(nIndex) + "_check", JsonBool (TRUE)); + } + json jLootFilter = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + jLootFilter = JsonArraySet(jLootFilter, 1, JsonInt(65535)); + ai_SetAssociateDbJson(oPC, sAssociateType, "lootfilters", jLootFilter); + DelayCommand(1.0, DeleteLocalInt(oPC, "AI_BLOCK_CHECKS")); + } + else if(sElem == "btn_clear_all") + { + SetLocalInt(oPC, "AI_BLOCK_CHECKS", TRUE); + SetLocalInt(oAssociate, sLootFilterVarname, 0); + int nIndex; + for(nIndex = 2; nIndex < 20; nIndex++) + { + NuiSetBind(oPC, nToken, "chbx_" + IntToString(nIndex) + "_check", JsonBool (FALSE)); + } + json jLootFilter = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + jLootFilter = JsonArraySet(jLootFilter, 1, JsonInt(0)); + ai_SetAssociateDbJson(oPC, sAssociateType, "lootfilters", jLootFilter); + DelayCommand(1.0, DeleteLocalInt(oPC, "AI_BLOCK_CHECKS")); + } + } + else if(sEvent == "watch") + { + if(GetStringLeft(sElem, 5) == "chbx_") + { + if(GetLocalInt(oPC, "AI_BLOCK_CHECKS")) return; + if(sElem == "chbx_give_loot_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_GIVE_TO_PC, nToken, sElem); + else if(sElem == "chbx_2_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_PLOT, nToken, sElem); + else if(sElem == "chbx_3_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_ARMOR, nToken, sElem); + else if(sElem == "chbx_4_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_BELTS, nToken, sElem); + else if(sElem == "chbx_5_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_BOOTS, nToken, sElem); + else if(sElem == "chbx_6_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_CLOAKS, nToken, sElem); + else if(sElem == "chbx_7_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_GEMS, nToken, sElem); + else if(sElem == "chbx_8_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_GLOVES, nToken, sElem); + else if(sElem == "chbx_9_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_HEADGEAR, nToken, sElem); + else if(sElem == "chbx_10_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_JEWELRY, nToken, sElem); + else if(sElem == "chbx_11_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_MISC, nToken, sElem); + else if(sElem == "chbx_12_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_POTIONS, nToken, sElem); + else if(sElem == "chbx_13_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_SCROLLS, nToken, sElem); + else if(sElem == "chbx_14_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_SHIELDS, nToken, sElem); + else if(sElem == "chbx_15_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_WANDS_RODS_STAVES, nToken, sElem); + else if(sElem == "chbx_16_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_WEAPONS, nToken, sElem); + else if(sElem == "chbx_17_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_ARROWS, nToken, sElem); + else if(sElem == "chbx_18_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_BOLTS, nToken, sElem); + else if(sElem == "chbx_19_check") ai_SetLootFilterToCheckbox(oPC, oAssociate, AI_LOOT_BULLETS, nToken, sElem); + json jLootFilter = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + int nLootFilter = GetLocalInt(oAssociate, sLootFilterVarname); + jLootFilter = JsonArraySet(jLootFilter, 1, JsonInt(nLootFilter)); + ai_SetAssociateDbJson(oPC, sAssociateType, "lootfilters", jLootFilter); + } + else if(GetStringLeft(sElem, 4) == "txt_") + { + if(sElem == "txt_max_weight") + { + int nMaxWeight = StringToInt(JsonGetString(NuiGetBind(oPC, nToken, sElem))); + if(nMaxWeight > 1000) nMaxWeight = 1000; + if(nMaxWeight < 1) nMaxWeight = 1; + SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, nMaxWeight); + json jLootFilter = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + jLootFilter = JsonArraySet(jLootFilter, 0, JsonInt(nMaxWeight)); + ai_SetAssociateDbJson(oPC, sAssociateType, "lootfilters", jLootFilter); + return; + } + if(GetStringLeft(sElem, 9) == "txt_gold_") + { + int nAmount = StringToInt(JsonGetString(NuiGetBind(oPC, nToken, sElem))); + int nIndex; + if(GetStringLength(sElem) == 11) nIndex = StringToInt(GetStringRight(sElem, 2)); + else nIndex = StringToInt(GetStringRight(sElem, 1)); + SetLocalInt(oAssociate, AI_MIN_GOLD_ + IntToString(nIndex), nAmount); + json jLootFilter = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + jLootFilter = JsonArraySet(jLootFilter, nIndex, JsonInt(nAmount)); + ai_SetAssociateDbJson(oPC, sAssociateType, "lootfilters", jLootFilter); + } + } + } + return; + } + //************************************************************************** + // Associate Paste events. + if(sWndId == sAssociateType + AI_COPY_NUI) + { + if(sEvent == "click") + { + int nIndex, nAssociateType = GetAssociateType(oAssociate); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + object oAssoc; + string sAssocType; + json jModes = ai_GetAssociateDbJson(oPC, sAssociateType, "modes"); + json jButtons = ai_GetAssociateDbJson(oPC, sAssociateType, "buttons"); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jLootFilters = ai_GetAssociateDbJson(oPC, sAssociateType, "lootfilters"); + string sCombatScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + string sDefaultScript = GetLocalString(oAssociate, AI_DEFAULT_SCRIPT); + if(sElem == "btn_paste_all") + { + // Check all non-henchman associates. + for(nIndex = 2; nIndex < 6; nIndex++) + { + if(nAssociateType != nIndex) + { + oAssoc = GetAssociate(nIndex, oPC); + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetAssociateDbJson(oPC, sAssocType, "modes", jModes); + ai_SetAssociateDbJson(oPC, sAssocType, "buttons", jButtons); + ai_SetAssociateDbJson(oPC, sAssocType, "aidata", jAIData); + ai_SetAssociateDbJson(oPC, sAssocType, "lootfilters", jLootFilters); + SetLocalString(oAssoc, AI_COMBAT_SCRIPT, sCombatScript); + SetLocalString(oAssoc, AI_DEFAULT_SCRIPT, sDefaultScript); + if(oAssoc != OBJECT_INVALID) + { + // Clear the creatures Perception distance so we can + // repopulate the local variables. + SetLocalFloat(oAssoc, AI_ASSOC_PERCEPTION_DISTANCE, 0.0); + ai_CheckAssociateData(oPC, oAssoc, sAssocType); + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType)) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssocType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssoc)); + } + } + } + } + // Check all of our henchman. + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssoc = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetAssociateDbJson(oPC, sAssocType, "modes", jModes); + ai_SetAssociateDbJson(oPC, sAssocType, "buttons", jButtons); + ai_SetAssociateDbJson(oPC, sAssocType, "aidata", jAIData); + ai_SetAssociateDbJson(oPC, sAssocType, "lootfilters", jLootFilters); + SetLocalString(oAssoc, AI_COMBAT_SCRIPT, sCombatScript); + SetLocalString(oAssoc, AI_DEFAULT_SCRIPT, sDefaultScript); + // Clear the creatures Perception distance so we can + // repopulate the local variables. + SetLocalFloat(oAssoc, AI_ASSOC_PERCEPTION_DISTANCE, 0.0); + ai_CheckAssociateData(oPC, oAssoc, sAssocType); + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType)) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssocType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssoc)); + } + } + else break; + } + ai_SendMessages(GetName(oAssociate) + "'s settings have been copied to all associates.", AI_COLOR_GREEN, oPC); + return; + } + else if(GetStringLeft(sElem, 18) == "btn_paste_henchman") + { + int nIndex = StringToInt(GetStringRight(sElem, 1)); + oAssoc = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssoc != OBJECT_INVALID) + { + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetAssociateDbJson(oPC, sAssocType, "modes", jModes); + ai_SetAssociateDbJson(oPC, sAssocType, "buttons", jButtons); + ai_SetAssociateDbJson(oPC, sAssocType, "aidata", jAIData); + ai_SetAssociateDbJson(oPC, sAssocType, "lootfilters", jLootFilters); + SetLocalString(oAssoc, AI_COMBAT_SCRIPT, sCombatScript); + SetLocalString(oAssoc, AI_DEFAULT_SCRIPT, sDefaultScript); + // Clear the creatures Perception distance so we can + // repopulate the local variables. + SetLocalFloat(oAssoc, AI_ASSOC_PERCEPTION_DISTANCE, 0.0); + ai_CheckAssociateData(oPC, oAssoc, sAssocType); + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType)) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssocType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssoc)); + } + ai_SendMessages(GetName(oAssociate) + "'s settings have been copied to " + GetName(oAssoc) + ".", AI_COLOR_GREEN, oPC); + } + return; + } + else if(sElem == "btn_paste_familiar") nIndex = ASSOCIATE_TYPE_FAMILIAR; + else if(sElem == "btn_paste_companion") nIndex = ASSOCIATE_TYPE_ANIMALCOMPANION; + else if(sElem == "btn_paste_summons") nIndex = ASSOCIATE_TYPE_SUMMONED; + else if(sElem == "btn_paste_dominated") nIndex = ASSOCIATE_TYPE_DOMINATED; + if(nIndex > 1 && nIndex < 6) + { + oAssoc = GetAssociate(nIndex, oPC); + sAssocType = ai_GetAssociateType(oPC, oAssoc); + ai_SetAssociateDbJson(oPC, sAssocType, "modes", jModes); + ai_SetAssociateDbJson(oPC, sAssocType, "buttons", jButtons); + ai_SetAssociateDbJson(oPC, sAssocType, "aidata", jAIData); + ai_SetAssociateDbJson(oPC, sAssocType, "lootfilters", jLootFilters); + SetLocalString(oAssoc, AI_COMBAT_SCRIPT, sCombatScript); + SetLocalString(oAssoc, AI_DEFAULT_SCRIPT, sDefaultScript); + if(oAssoc != OBJECT_INVALID) + { + // Clear the creatures Perception distance so we can + // repopulate the local variables. + SetLocalFloat(oAssoc, AI_ASSOC_PERCEPTION_DISTANCE, 0.0); + ai_CheckAssociateData(oPC, oAssoc, sAssocType); + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType)) + { + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssocType + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssoc)); + } + ai_SendMessages(GetName(oAssociate) + "'s settings have been copied to " + GetName(oAssoc) + ".", AI_COLOR_GREEN, oPC); + } + } + } + return; + } + //************************************************************************** + // Plugins events. + if(sWndId == AI_PLUGIN_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_load_plugins") + { + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_buffing"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_forcerest"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_henchmen"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_crafting"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_mod_set"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_debug"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_test"); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + } + if(sElem == "btn_load_m_mods") + { + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, "mm_prc_spells"); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + } + if(sElem == "btn_check_plugins") + { + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + if(JsonGetInt(JsonArrayGet(jPlugin, 1)) < 3) + { + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(TRUE)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + if(sElem == "btn_clear_plugins") + { + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + if(JsonGetInt(JsonArrayGet(jPlugin, 1)) < 3) + { + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(FALSE)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + else if(sElem == "btn_add_plugin") + { + string sScript = JsonGetString(NuiGetBind (oPC, nToken, "txt_plugin")); + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + jPlugins = ai_Plugin_Add(oPC, jPlugins, sScript); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + } + else if(GetStringLeft(sElem, 18) == "btn_remove_plugin_") + { + int nIndex = StringToInt(GetStringRight(sElem, 1)); + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + jPlugins = JsonArrayDel(jPlugins, nIndex); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreatePluginNUI(oPC)); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oPC, sElem); + } + else if(sEvent == "watch") + { + if(GetStringLeft(sElem, 12) == "chbx_plugin_" && GetStringRight(sElem, 6) == "_check") + { + int nIndex = StringToInt(GetSubString(sElem, 12, 1)); + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + json jPlugin = JsonArrayGet(jPlugins, nIndex); + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + } + return; + } + //************************************************************************** + // Quick Use Widget events. + if(sWndId == sAssociateType + AI_QUICK_WIDGET_NUI) + { + if(sEvent == "click") + { + if(GetStringLeft(sElem, 10) == "btn_class_") // Changes the class. + { + string sClassPosition = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 0, JsonInt(StringToInt(sClassPosition))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateQuickWidgetSelectionNUI(oPC, oAssociate)); + } + else if(GetStringLeft(sElem, 10) == "btn_level_") // Changes the level. + { + string sLevel; + if(GetStringLength(sElem) == 12) sLevel = GetStringRight(sElem, 2); + else sLevel = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 1, JsonInt(StringToInt(sLevel))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateQuickWidgetSelectionNUI(oPC, oAssociate)); + } + else if(sElem == "btn_text_spell") // Adds abilities to quick use widget. + { + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + if(JsonGetType(jWidget) == JSON_TYPE_NULL) + { + jWidget = JsonArray(); + if(JsonGetLength(jSpells) == 2) jSpells = JsonArrayInsert(jSpells, JsonArray()); + } + if(JsonGetLength(jWidget) < 20) + { + json jData = NuiGetUserData(oPC, nToken); + json jQuickListArray = JsonArrayGet(jData, 1); + json jSpell = JsonArrayGet(jQuickListArray, nIndex); + jWidget = JsonArrayInsert(jWidget, jSpell); + jSpells = JsonArraySet(jSpells, 2, jWidget); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateQuickWidgetSelectionNUI(oPC, oAssociate)); + } + else ai_SendMessages("The quick widget can only have 20 abilities or spells!", AI_COLOR_RED, oPC); + } + else if(sElem == "btn_info_spell") + { + json jQuickListArray = JsonArrayGet(jData, 1); + json jSpell = JsonArrayGet(jQuickListArray, nIndex); + ai_CreateDescriptionNUI(oPC, jSpell); + } + else if(GetStringLeft(sElem, 11) == "btn_widget_") + { + string sIndex; + if(GetStringLength(sElem) == 13) sIndex = GetStringRight(sElem, 2); + else sIndex = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + jWidget = JsonArrayDel(jWidget, StringToInt(sIndex)); + jSpells = JsonArraySet(jSpells, 2, jWidget); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateQuickWidgetSelectionNUI(oPC, oAssociate)); + } + } + else if(sEvent == "close") + { + int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI); + if(nUIToken) + { + DelayCommand(0.0, NuiDestroy(oPC, nUIToken)); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + } + return; + } + //************************************************************************** + // Spell Memorization events. + if(sWndId == sAssociateType + AI_SPELL_MEMORIZE_NUI) + { + if(sEvent == "click") + { + if(GetStringLeft(sElem, 10) == "btn_class_") // Changes the class. + { + string sClassPosition = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 0, JsonInt(StringToInt(sClassPosition))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateSpellMemorizationNUI(oPC, oAssociate)); + } + else if(GetStringLeft(sElem, 10) == "btn_level_") // Changes the level. + { + string sLevel = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 1, JsonInt(StringToInt(sLevel))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateSpellMemorizationNUI(oPC, oAssociate)); + } + else if(sElem == "btn_text_spell") // Adds spell to memorization. + { + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + int nClass = GetClassByPosition(JsonGetInt(JsonArrayGet(jSpells, 0)), oAssociate); + int nLevel = JsonGetInt(JsonArrayGet(jSpells, 1)); + json jSpellArray = JsonArrayGet(jData, 1); + int nMaxMemorizationSlot = GetMemorizedSpellCountByLevel(oAssociate, nClass, nLevel); + int nSlot, nSpell; + while(nSlot < nMaxMemorizationSlot) + { + if(GetMemorizedSpellId(oAssociate, nClass, nLevel, nSlot) == -1) + { + nSpell = JsonGetInt(JsonArrayGet(jSpellArray, nIndex)); + SetMemorizedSpell(oAssociate, nClass, nLevel, nSlot, nSpell, FALSE); + //NuiDestroy(oPC, nToken); + //ai_CreateSpellMemorizationNUI(oPC, oAssociate); + string sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + string sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + string sIndex = IntToString(nSlot); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + return; + } + nSlot++; + } + if(nSlot >= nMaxMemorizationSlot) ai_SendMessages("All spell memorization slots are full!", AI_COLOR_RED, oPC); + } + else if(sElem == "btn_info_spell") + { + json jSpellArray = JsonArrayGet(jData, 1); + int nSpell = JsonGetInt(JsonArrayGet(jSpellArray, nIndex)); + ai_CreateDescriptionNUI(oPC, JsonArray(), nSpell); + } + else if(GetStringLeft(sElem, 14) == "btn_memorized_") + { + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + int nClass = GetClassByPosition(JsonGetInt(JsonArrayGet(jSpells, 0)), oAssociate); + int nLevel = JsonGetInt(JsonArrayGet(jSpells, 1)); + string sIndex = GetStringRight(sElem, 1); + ClearMemorizedSpell(oAssociate, nClass, nLevel, StringToInt(sIndex)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_tooltip", JsonString("")); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_event", JsonBool(FALSE)); + //NuiDestroy(oPC, nToken); + //ai_CreateSpellMemorizationNUI(oPC, oAssociate); + } + } + else if(sEvent == "close") + { + int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI); + if(nUIToken) + { + DelayCommand(0.0, NuiDestroy(oPC, nUIToken)); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + } + return; + } + //************************************************************************** + // Spell Known events. + if(sWndId == sAssociateType + AI_SPELL_KNOWN_NUI) + { + if(sEvent == "click") + { + if(GetStringLeft(sElem, 10) == "btn_class_") // Changes the class. + { + string sClassPosition = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 0, JsonInt(StringToInt(sClassPosition))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateSpellKnownNUI(oPC, oAssociate)); + } + else if(GetStringLeft(sElem, 10) == "btn_level_") // Changes the level. + { + string sLevel = GetStringRight(sElem, 1); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + jSpells = JsonArraySet(jSpells, 1, JsonInt(StringToInt(sLevel))); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateSpellKnownNUI(oPC, oAssociate)); + } + else if(sElem == "btn_text_spell") // Adds spell to known list. + { + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + int nClass = GetClassByPosition(JsonGetInt(JsonArrayGet(jSpells, 0)), oAssociate); + int nLevel = JsonGetInt(JsonArrayGet(jSpells, 1)); + json jSpellArray = JsonArrayGet(jData, 1); + int nSpell = JsonGetInt(JsonArrayGet(jSpellArray, nIndex)); + json jClassList = GetLocalJson(oAssociate, AI_CLASS_LIST_JSON); + // Get the correct class array. + int bAddList, nClassIndex = 0; + json jClass = JsonArrayGet(jClassList, nClassIndex); + while(JsonGetInt(GffGetInt(jClass, "Class")) != nClass) + { + jClass = JsonArrayGet(jClassList, ++nClassIndex); + } + string sLevel = IntToString(nLevel); + json jSpell, jKnownList = GffGetList(jClass, "KnownList" + sLevel); + if(JsonGetType(jKnownList) == JSON_TYPE_NULL) + { + bAddList = TRUE; + jKnownList = JsonArray(); + } + int nMaxKnownSlots, nSlot; + string sSpellKnownTable = Get2DAString("classes", "SpellKnownTable", nClass); + if(sSpellKnownTable != "") nMaxKnownSlots = StringToInt(Get2DAString(sSpellKnownTable, "SpellLevel" + sLevel, GetLevelByClass(nClass, oAssociate) - 1)); + else nMaxKnownSlots = 20; + while(nSlot < nMaxKnownSlots) + { + jSpell = JsonArrayGet(jKnownList, nSlot); + if(JsonGetType(jSpell) == JSON_TYPE_NULL) + { + jSpell = GffAddWord(JsonObject(), "Spell", nSpell); + jSpell = JsonObjectSet(jSpell, "__struct_id", JsonInt(3)); + jKnownList = JsonArrayInsert(jKnownList, jSpell); + string sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + string sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + string sIndex = IntToString(nSlot); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + sLevel + ")")); + SetLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE", TRUE); + break; + } + else if(JsonGetInt(GffGetWord(jSpell, "Spell")) == nSpell) + { + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_SendMessages(sName + " is already in the known spell list!", AI_COLOR_RED, oPC); + return; + } + nSlot++; + } + if(nSlot >= nMaxKnownSlots) + { + ai_SendMessages("All known spell slots are full!", AI_COLOR_RED, oPC); + return; + } + if(bAddList) jClass = GffAddList(jClass, "KnownList" + sLevel, jKnownList); + else jClass = GffReplaceList(jClass, "KnownList" + sLevel, jKnownList); + jClassList = JsonArraySet(jClassList, nClassIndex, jClass); + SetLocalJson(oAssociate, AI_CLASS_LIST_JSON, jClassList); + } + else if(sElem == "btn_info_spell") + { + json jSpellArray = JsonArrayGet(jData, 1); + int nSpell = JsonGetInt(JsonArrayGet(jSpellArray, nIndex)); + ai_CreateDescriptionNUI(oPC, JsonArray(), nSpell); + } + else if(GetStringLeft(sElem, 10) == "btn_known_") // Remove a known spell. + { + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + int nClass = GetClassByPosition(JsonGetInt(JsonArrayGet(jSpells, 0)), oAssociate); + int nLevel = JsonGetInt(JsonArrayGet(jSpells, 1)); + string sIndex = GetStringRight(sElem, 1); + // Check to see if there is a spell in this slot. + string sImageName = JsonGetString(NuiGetBind(oPC, nToken, "btn_known_" + sIndex + "_image")); + if(sImageName == "ctl_cg_btn_splvl") return; + json jClassList = GetLocalJson(oAssociate, AI_CLASS_LIST_JSON); + // Get the correct class array. + int nClassIndex = 0; + json jClass = JsonArrayGet(jClassList, nClassIndex); + while(JsonGetInt(GffGetInt(jClass, "Class")) != nClass) + { + jClass = JsonArrayGet(jClassList, ++nClassIndex); + } + string sLevel = IntToString(nLevel); + json jKnownList = GffGetList(jClass, "KnownList" + sLevel); + jKnownList = JsonArrayDel(jKnownList, StringToInt(sIndex)); + jClass = GffReplaceList(jClass, "KnownList" + sLevel, jKnownList); + jClassList = JsonArraySet(jClassList, nClassIndex, jClass); + SetLocalJson(oAssociate, AI_CLASS_LIST_JSON, jClassList); + SetLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE", TRUE); + // Relist all known spells so they match the index. + int nMaxKnownSlots, nSpell; + string sName, sSpellIcon, sClass = IntToString(nClass); + string sSpellKnownTable = Get2DAString("classes", "SpellKnownTable", nClass); + json jSpell; + if(sSpellKnownTable != "") nMaxKnownSlots = StringToInt(Get2DAString(sSpellKnownTable, "SpellLevel" + IntToString(nLevel), GetLevelByClass(nClass, oAssociate) - 1)); + else nMaxKnownSlots = 20; + nIndex = 0; + while(nIndex < 20) + { + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_event", JsonBool(TRUE)); + if(nIndex < nMaxKnownSlots) + { + jSpell = JsonArrayGet(jKnownList, nIndex); + if(JsonGetType(jSpell) == JSON_TYPE_NULL) + { + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_tooltip", JsonString(" Empty known spell slot")); + } + else + { + nSpell = JsonGetInt(GffGetWord(jSpell, "Spell")); + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + //nMetaMagic = 255; + //nDomain = 0; + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + //sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, -1, -1, -1, nMetaMagic, nDomain); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + } + } + else + { + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString("")); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_event", JsonBool(FALSE)); + } + ++nIndex; + } + } + } + else if(sEvent == "close") + { + if(GetLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE")) + { + RemoveHenchman(oPC, oAssociate); + json jHenchman = ObjectToJson(oAssociate, TRUE); + json jClassList = GetLocalJson(oAssociate, AI_CLASS_LIST_JSON); + jHenchman = GffReplaceList(jHenchman, "ClassList", jClassList); + location lLocation = GetLocation(oAssociate); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oAssociate); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oAssociate); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + AssignCommand(oAssociate, SetIsDestroyable(TRUE, FALSE, FALSE)); + DestroyObject(oAssociate); + oAssociate = ai_AddHenchman(oPC, jHenchman, lLocation, nFamiliar, nCompanion); + DeleteLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE"); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + } + } + return; + } + //************************************************************************** + // Spell Description events. + if(sWndId == AI_SPELL_DESCRIPTION_NUI) + { + if(sEvent == "click" && sElem == "btn_ok") DelayCommand(0.0, NuiDestroy(oPC, nToken)); + } + //************************************************************************** + // Effect Icon NUI events. + if(sWndId == AI_EFFECT_ICON_NUI) + { + if(sEvent == "click") + { + if(GetStringLeft(sElem, 18) == "btn_remove_effect_") + { + int nEffectIndex = StringToInt(GetStringRight(sElem, GetStringLength(sElem) - 18)); + json jEffectID = JsonArrayGet(jData, 2); + string sEffectLinkID = JsonGetString(JsonArrayGet(jEffectID, nEffectIndex)); + int nIndex; + effect eEffect = GetFirstEffect(oPC); + while(GetIsEffectValid(eEffect)) + { + if(GetEffectLinkId(eEffect) == sEffectLinkID) + { + RemoveEffect(oPC, eEffect); + int nEffectIconToken = NuiFindWindow(oPC, AI_EFFECT_ICON_NUI); + if(nEffectIconToken) DelayCommand(0.0, NuiDestroy(oPC, nEffectIconToken)); + } + nIndex++; + eEffect = GetNextEffect(oPC); + } + } + } + else if(sEvent == "mousedown") + { + AssignCommand(oPC, PlaySound("gui_button")); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + } + } +} +void ai_SetWidgetButtonToCheckbox(object oPC, int nButton, object oAssociate, string sAssociateType, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + ai_SetWidgetButton(oPC, nButton, oAssociate, sAssociateType, bCheck); +} +void ai_SetAIButtonToCheckbox(object oPC, int nButton, object oAssociate, string sAssociateType, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + ai_SetAIButton(oPC, nButton, oAssociate, sAssociateType, bCheck); +} +void ai_SetLootFilterToCheckbox(object oPC, object oAssociate, int nFilterBit, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + ai_SetLootFilter(oAssociate, nFilterBit, bCheck); +} +void ai_AddAssociate(object oPC, int nToken, json jAssociate, location lLocation, int nFamiliar, int nCompanion, int nRange = 0) +{ + object oAssociate = JsonToObject(jAssociate, lLocation, OBJECT_INVALID, TRUE); + //ChangeToStandardFaction(oAssociate, STANDARD_FACTION_COMMONER); + //SetStandardFactionReputation(STANDARD_FACTION_COMMONER, 50, oAssociate); + //SetStandardFactionReputation(STANDARD_FACTION_DEFENDER, 50, oAssociate); + //SetStandardFactionReputation(STANDARD_FACTION_MERCHANT, 50, oAssociate); + //SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 0, oAssociate); + AddHenchman(oPC, oAssociate); + DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE"); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + if(nRange) SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, nRange); + if(nFamiliar) SummonFamiliar(oAssociate); + if(nCompanion) SummonAnimalCompanion(oAssociate); +} +void ai_SetCompanionType(object oPC, object oAssociate, int nToken, int nAssociateType) +{ + if(ai_GetIsCharacter(oAssociate)) return; + SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); + int nSelection; + // Need to remove the henchman before we copy them to keep factions correct. + ai_FireHenchman(oPC, oAssociate); + json jAssociate = ObjectToJson(oAssociate, TRUE); + if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) + { + nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_familiar_selected")); + jAssociate = GffReplaceInt(jAssociate, "FamiliarType", nSelection); + } + else if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) + { + nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_companion_selected")); + jAssociate = GffReplaceInt(jAssociate, "CompanionType", nSelection); + } + //ai_Debug("0e_nui", "916", JsonDump(jAssociate, 1)); + location lLocation = GetLocation(oAssociate); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oAssociate); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oAssociate); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate); + DestroyObject(oAssociate); + DelayCommand(0.1, ai_AddAssociate(oPC, nToken, jAssociate, lLocation, nFamiliar, nCompanion)); +} +void ai_SetCompanionName(object oPC, object oAssociate, int nToken, int nAssociateType) +{ + if(ai_GetIsCharacter(oAssociate)) return; + SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); + string sAssociateType; + string sName; + // Need to remove the henchman before we copy them to keep factions correct. + ai_FireHenchman(oPC, oAssociate); + json jAssociate = ObjectToJson(oAssociate, TRUE); + if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) + { + sName = JsonGetString(NuiGetBind(oPC, nToken, "txt_familiar_name")); + jAssociate = GffReplaceString(jAssociate, "FamiliarName", sName); + } + else if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) + { + sAssociateType = "txt_companion_name"; + sName = JsonGetString(NuiGetBind(oPC, nToken, "txt_companion_name")); + jAssociate = GffReplaceString(jAssociate, "FamiliarName", sName); + } + location lLocation = GetLocation(oAssociate); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oAssociate); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oAssociate); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate); + DestroyObject(oAssociate); + DelayCommand(0.1, ai_AddAssociate(oPC, nToken, jAssociate, lLocation, nFamiliar, nCompanion)); +} +void ai_SetAIScript(object oPC, object oAssociate, int nToken) +{ + int nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_ai_script_selected")); + if(nSelection == 0) return; + string sScript = sScript = ResManFindPrefix("ai_a_", RESTYPE_NCS, nSelection); + NuiSetBind(oPC, nToken, "txt_ai_script", JsonString(sScript)); + string sOldScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + if(sScript != sOldScript) + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + if(JsonGetType(JsonArrayGet(jAIData, 8)) == JSON_TYPE_NULL) jAIData = JsonArrayInsert(jAIData, JsonString(sScript)); + else jAIData = JsonArraySet(jAIData, 8, JsonString(sScript)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + ai_SendMessages(GetName(oAssociate) + " is now using " + sScript + " AI script!", AI_COLOR_GREEN, oPC); + } + else ai_SendMessages(GetName(oAssociate) + " is already using this script! Did not change AI script.", AI_COLOR_RED, oPC); +} +void ai_PercRangeIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType, int nToken) +{ + int nAdjustment = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU"); + nAdjustment += nIncrement; + if(nAdjustment < 8 || nAdjustment > 11) return; + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU", nAdjustment); + json jAssociate = ObjectToJson(oAssociate, TRUE); + int nHenchPercRange = JsonGetInt(GffGetByte(jAssociate, "PerceptionRange")); + string sText, sInfo; + if(nAdjustment == nHenchPercRange) + { + if(nAdjustment == 8) sText = " Perception Range Short [10 meters Sight / 10 meters Listen]"; + else if(nAdjustment == 9) sText = " Perception Range Medium [20 meters Sight / 20 meters Listen]"; + else if(nAdjustment == 10) sText = " Perception Range Long [35 meters Sight / 20 meters Listen]"; + else sText = " Perception Range Default [20 meters Sight / 20 meters Listen]"; + sInfo = " "; + } + else + { + if(nAdjustment == 8) sText = " !!! Click the Perception Range button to set to short range !!!"; + else if(nAdjustment == 9) sText = " !!! Click the Perception Range button to set to medium range !!!"; + else if(nAdjustment == 10) sText = " !!! Click the Perception Range button to set to long range !!!"; + else sText = " !!! Click the Perception Range button to set to the default range !!!"; + sInfo = sText; + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_perc_range_tooltip", sText); + if(nToken > -1) NuiSetBind (oPC, nToken, "lbl_info_label", JsonString(sInfo)); +} +void ai_Perc_Range(object oPC, object oAssociate, int nToken, string sAssociateType) +{ + if(ai_GetIsCharacter(oAssociate)) return; + SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); + int nBtnPercRange = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU"); + string sText, sText2; + float fRange = 20.0; + if(nBtnPercRange == 8) + { + sText = "short"; + sText2 = " Perception Range Short [10 meters Sight / 10 meters Listen]"; + fRange = 10.0; + } + else if(nBtnPercRange == 9) + { + sText = "medium"; + sText2 = " Perception Range Medium [20 meters Sight / 20 meters Listen]"; + } + else if(nBtnPercRange == 10) + { + sText = "long"; + sText2 = " Perception Range Long [35 meters Sight / 20 meters Listen]"; + fRange = 35.0; + } + else if(nBtnPercRange == 11) + { + sText = "default"; + sText2 = " Perception Range Default [20 meters Sight / 20 meters Listen]"; + } + SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, fRange); + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, nBtnPercRange); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 7, JsonInt(nBtnPercRange)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + // Need to remove the henchman before we copy them to keep factions correct. + ai_FireHenchman(oPC, oAssociate); + json jAssociate = ObjectToJson(oAssociate, TRUE); + int nHenchPercRange = JsonGetInt(GffGetByte(jAssociate, "PerceptionRange")); + if(nBtnPercRange == nHenchPercRange) + { + ai_SendMessages(GetName(oAssociate) + " already has this perception set.", AI_COLOR_YELLOW, oPC); + AddHenchman(oPC, oAssociate); + DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE"); + return; + } + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_NUI))); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_perc_range_tooltip", sText2); + ai_SendMessages(GetName(oAssociate) + " has updated their perception range to " + sText + ".", AI_COLOR_YELLOW, oPC); + location lLocation = GetLocation(oAssociate); + jAssociate = GffReplaceByte(jAssociate, "PerceptionRange", nBtnPercRange); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oAssociate); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oAssociate); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate); + DestroyObject(oAssociate); + DelayCommand(0.1, ai_AddAssociate(oPC, nToken, jAssociate, lLocation, nFamiliar, nCompanion, nBtnPercRange)); +} +void ai_RulePercDistInc(object oPC, object oModule, int nIncrement, int nToken) +{ + int nAdjustment = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE) + nIncrement; + if(nAdjustment < 8 || nAdjustment > 11) return; + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, nAdjustment); + string sText; + if(nAdjustment == 8) sText = " Monster perception: Short [10 Sight / 10 Listen]"; + else if(nAdjustment == 9) sText = " Monster perception: Medium [20 Sight / 20 Listen]"; + else if(nAdjustment == 10) sText = " Monster perception: Long [35 Sight / 20 Listen]"; + else sText = " Monster perception: Default [Monster's default values]"; + NuiSetBind(oPC, nToken, "lbl_perc_dist_label", JsonString(sText)); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_MON_PERC_DISTANCE, JsonInt(nAdjustment)); + ai_SetCampaignDbJson("rules", jRules); +} +json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE) +{ + object oModule = GetModule(); + json jRSpells = GetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS); + if(JsonGetType(jRSpells) == JSON_TYPE_NULL) jRSpells = JsonArray(); + int nIndex, nMaxIndex = JsonGetLength(jRSpells); + if(bRestrict) + { + while(nIndex < nMaxIndex) + { + if(JsonGetInt(JsonArrayGet(jRSpells, nIndex)) == nSpell) return jRules; + nIndex++; + } + jRSpells = JsonArrayInsert(jRSpells, JsonInt(nSpell)); + } + else + { + while(nIndex < nMaxIndex) + { + if(JsonGetInt(JsonArrayGet(jRSpells, nIndex)) == nSpell) + { + jRSpells = JsonArrayDel(jRSpells, nIndex); + break; + } + nIndex++; + } + } + SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, jRSpells); + return JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, jRSpells); +} +void ai_TurnOn(object oPC, object oTarget, string sAssociateType) +{ + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI On"); + ai_SendMessages("AI turned on for " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "xx_pc_1_hb"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_NOTICE, "xx_pc_2_percept"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "xx_pc_3_endround"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "xx_pc_4_convers"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "xx_pc_5_phyatked"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "xx_pc_6_damaged"); + //SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DEATH, ""); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "xx_pc_8_disturb"); + //SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_RESTED, ""); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "xx_pc_b_castat"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "xx_pc_e_blocked"); + //SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); + // This sets the script for the PC to run AI based on class. + ai_SetAssociateAIScript(oTarget, FALSE); + // Set so PC can hear associates talking in combat. + ai_SetListeningPatterns(oTarget); +} +void ai_TurnOff(object oPC, object oAssociate, string sAssociateType) +{ + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI Off"); + ai_SendMessages("AI Turned off for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_NOTICE, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DAMAGED, ""); + //SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DEATH, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DISTURBED, ""); + //SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_RESTED, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, ""); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, ""); + //SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); + DeleteLocalInt(oAssociate, "AI_I_AM_BEING_HEALED"); + DeleteLocalString(oAssociate, "AIScript"); + ai_ClearCreatureActions(); +} +object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion) +{ + jHenchman = GffReplaceResRef(jHenchman, "ScriptSpawn", ""); + object oHenchman = JsonToObject(jHenchman, lLocation, OBJECT_INVALID, TRUE); + AddHenchman(oPC, oHenchman); + DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE"); + string sAssociateType = ai_GetAssociateType(oPC, oHenchman); + NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)); + if(nFamiliar) SummonFamiliar(oHenchman); + if(nCompanion) SummonAnimalCompanion(oHenchman); + return oHenchman; +} + diff --git a/src/module/nss/0e_nui_dm.nss b/src/module/nss/0e_nui_dm.nss new file mode 100644 index 0000000..4ffd851 --- /dev/null +++ b/src/module/nss/0e_nui_dm.nss @@ -0,0 +1,700 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: 0e_nui_dm + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Menu event script + sEvent: close, click, mousedown, mouseup, watch (if bindwatch is set). +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_menus_dm" +void ai_SetDMWidgetButtonToCheckbox(object oDM, int nButton, int nToken, string sElem); +void ai_SetDMWAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem); +void ai_SetDMAIAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem); +void ai_SetDMAIAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem); +void ai_RulePercDistInc(object oDM, object oModule, int nIncrement, int nToken); +// Adds a spell to a json AI restricted spell list then returns jRules. +// bRestrict = TRUE will add to the list FALSE will remove it from the list. +json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE); +// Adds a selected creature to the group. +void ai_SelectToGroup(object oDM, string sElem); +// Does a selected action for nGroup. +void ai_DMSelectAction(object oDM, string sElem); +// Changes if the group will run (nSpeed: 1) or walk (nSpeed: 0). +void ai_DMChangeMoveSpeed(object oDM, string sElem, int nSpeed); +void main() +{ + object oDM = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + string sWndId = NuiGetWindowId(oDM, nToken); + //if(AI_DEBUG) ai_Debug ("0e_nui", "58", "sWndId: " + sWndId + " sEvent: " + sEvent + " sElem: " + sElem + + // " nToken: " + IntToString(nToken) + " oPC: " + GetName(oPC)); + //WriteTimestampedLogEntry("0e_nui, 58, sWndId: " + sWndId + " sEvent: " + sEvent + " sElem: " + sElem + + // " nToken: " + IntToString(nToken) + " oDM: " + GetName(oDM)); + //************************************************************************** + string sName = ai_RemoveIllegalCharacters(GetName(oDM)); + // Watch to see if the window moves and save. + if(sElem == "window_geometry" && sEvent == "watch") + { + if(GetLocalInt(oDM, AI_NO_NUI_SAVE)) return; + SaveMenuToCampaignDb(oDM, nToken, sWndId); + } + //************************************************************************** + // Widget events. + if(sWndId == "dm" + AI_WIDGET_NUI) + { + //if(GetLocalInt(oDM, AI_NO_NUI_SAVE)) return; + if(sEvent == "click") + { + if(sElem == "btn_open_main") + { + if(IsWindowClosed(oDM, "dm" + AI_COMMAND_NUI)) ai_CreateDMCommandNUI(oDM); + IsWindowClosed(oDM, "dm" + AI_MAIN_NUI); + } + else if(sElem == "btn_camera") ai_SelectCameraView(oDM); + else if(sElem == "btn_inventory") ai_SelectOpenInventory(oDM); + else if(GetStringLeft(sElem, 13) == "btn_cmd_group") + { + ai_DMSelectAction(oDM, sElem); + } + else if(GetStringLeft(sElem, 15) == "btn_exe_plugin_") ai_Plugin_Execute(oDM, sElem, TRUE); + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + if(GetStringLeft(sElem, 13) == "btn_cmd_group") ai_DMChangeMoveSpeed(oDM, sElem, 1); + } + if(nMouseScroll == -1.0) // Scroll down + { + if(GetStringLeft(sElem, 13) == "btn_cmd_group") ai_DMChangeMoveSpeed(oDM, sElem, 0); + } + } + else if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + if(sElem == "btn_open_main") + { + if(IsWindowClosed(oDM, "dm" + AI_MAIN_NUI)) ai_CreateDMOptionsNUI(oDM); + } + else if(GetStringLeft(sElem, 13) == "btn_cmd_group") + { + ai_SelectToGroup(oDM, sElem); + } + } + } + } + else if(sWndId == "dm" + AI_COMMAND_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_widget_lock") + { + if(ai_GetDMWidgetButton(oDM, BTN_DM_WIDGET_LOCK)) + { + ai_SendMessages(GetName(oDM) + " AI widget unlocked.", AI_COLOR_YELLOW, oDM); + ai_SetDMWidgetButton(oDM, BTN_DM_WIDGET_LOCK, FALSE); + } + else + { + ai_SendMessages(GetName(oDM) + " AI widget locked.", AI_COLOR_YELLOW, oDM); + ai_SetDMWidgetButton(oDM, BTN_DM_WIDGET_LOCK, TRUE); + } + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + else if(sElem == "btn_main_menu") + { + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMOptionsNUI(oDM)); + } + else if(sElem == "btn_camera") ai_SelectCameraView(oDM); + else if(sElem == "btn_inventory") ai_SelectOpenInventory(oDM); + else if(GetStringLeft(sElem, 13) == "btn_cmd_group") ai_DMSelectAction(oDM, sElem); + else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oDM, sElem, 1); + } + else if(sEvent == "watch") + { + if(sElem == "chbx_cmd_group1_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP1, nToken, sElem); + else if(sElem == "chbx_cmd_group2_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP2, nToken, sElem); + else if(sElem == "chbx_cmd_group3_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP3, nToken, sElem); + else if(sElem == "chbx_cmd_group4_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP4, nToken, sElem); + else if(sElem == "chbx_cmd_group5_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP5, nToken, sElem); + else if(sElem == "chbx_cmd_group6_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_GROUP6, nToken, sElem); + else if(sElem == "chbx_camera_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_CAMERA, nToken, sElem); + else if(sElem == "chbx_inventory_check") ai_SetDMWidgetButtonToCheckbox(oDM, BTN_DM_CMD_INVENTORY, nToken, sElem); + if(GetStringLeft(sElem, 12) == "chbx_plugin_" && GetStringRight(sElem, 6) == "_check") + { + int nIndex = StringToInt(GetSubString(sElem, 12, 1)); + json jPlugins = ai_GetCampaignDbJson("plugins", sName, AI_DM_TABLE); + json jPlugin = JsonArrayGet(jPlugins, nIndex); + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + ai_SetCampaignDbJson("plugins", jPlugins, sName, AI_DM_TABLE); + } + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + if(GetStringLeft(sElem, 13) == "btn_cmd_group") ai_DMChangeMoveSpeed(oDM, sElem, 1); + } + if(nMouseScroll == -1.0) // Scroll down + { + if(GetStringLeft(sElem, 13) == "btn_cmd_group") ai_DMChangeMoveSpeed(oDM, sElem, 0); + } + } + else if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + if(GetStringLeft(sElem, 13) == "btn_cmd_group") + { + ai_SelectToGroup(oDM, sElem); + } + } + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + } + else if(nMouseScroll == -1.0) // Scroll down + { + } + } + } + //************************************************************************** + // Main AI events. + if(sWndId == "dm" + AI_MAIN_NUI) + { + if(sEvent == "click") + { + if(sElem == "btn_plugin_manager") + { + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + } + if(sElem == "btn_widget_manager") + { + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMWidgetManagerNUI(oDM)); + } + } + if(sEvent == "watch") + { + if(sElem == "txt_max_henchman") + { + int nMaxHenchmen = StringToInt(JsonGetString(NuiGetBind(oDM, nToken, sElem))); + if(nMaxHenchmen < 1) nMaxHenchmen = 1; + if(nMaxHenchmen > 12) + { + nMaxHenchmen = 12; + ai_SendMessages("The maximum henchmen for this mod is 12!", AI_COLOR_RED, oDM); + } + SetMaxHenchmen(nMaxHenchmen); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_MAX_HENCHMAN, JsonInt(nMaxHenchmen)); + ai_SetCampaignDbJson("rules", jRules); + ai_SendMessages("Maximum henchmen has been changed to " + IntToString(nMaxHenchmen), AI_COLOR_YELLOW, oDM); + } + else if(sElem == "txt_ai_difficulty") + { + int nChance = StringToInt(JsonGetString(NuiGetBind(oDM, nToken, sElem))); + if(nChance < 0) nChance = 0; + else if(nChance > 100) nChance = 100; + SetLocalInt(GetModule(), AI_RULE_AI_DIFFICULTY, nChance); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_AI_DIFFICULTY, JsonInt(nChance)); + ai_SetCampaignDbJson("rules", jRules); + } + else if(sElem == "txt_perception_distance") + { + float fDistance = StringToFloat(JsonGetString(NuiGetBind(oDM, nToken, sElem))); + if(fDistance < 10.0) fDistance = 10.0; + else if(fDistance > 60.0) fDistance = 60.0; + SetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE, fDistance); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_PERCEPTION_DISTANCE, JsonFloat(fDistance)); + ai_SetCampaignDbJson("rules", jRules); + } + else if(sElem == "txt_inc_hp") + { + int nNumber = StringToInt(JsonGetString(NuiGetBind(oDM, nToken, sElem))); + if(nNumber < 0) nNumber = 0; + else if(nNumber > 100) nNumber = 100; + SetLocalInt(GetModule(), AI_INCREASE_MONSTERS_HP, nNumber); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(nNumber)); + ai_SetCampaignDbJson("rules", jRules); + } + else if(GetStringLeft(sElem, 4) == "chbx") + { + object oModule = GetModule(); + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + json jRules = ai_GetCampaignDbJson("rules"); + if(sElem == "chbx_moral_check") + { + SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_MORAL_CHECKS, JsonInt(bCheck)); + } + else if(sElem == "chbx_buff_monsters_check") + { + SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(bCheck)); + } + else if(sElem == "chbx_buff_summons_check") + { + SetLocalInt(oModule, AI_RULE_PRESUMMON, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PRESUMMON, JsonInt(bCheck)); + } + else if(sElem == "chbx_ambush_monsters_check") + { + SetLocalInt(oModule, AI_RULE_AMBUSH, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_AMBUSH, JsonInt(bCheck)); + } + else if(sElem == "chbx_companions_check") + { + SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_SUMMON_COMPANIONS, JsonInt(bCheck)); + } + else if(sElem == "chbx_advanced_movement_check") + { + SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ADVANCED_MOVEMENT, JsonInt(bCheck)); + } + else if(sElem == "chbx_ilr_check") + { + SetLocalInt(oModule, AI_RULE_ILR, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ILR, JsonInt(bCheck)); + } + else if(sElem == "chbx_umd_check") + { + SetLocalInt(oModule, AI_RULE_ALLOW_UMD, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_ALLOW_UMD, JsonInt(bCheck)); + } + else if(sElem == "chbx_use_healingkits_check") + { + SetLocalInt(oModule, AI_RULE_HEALERSKITS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_HEALERSKITS, JsonInt(bCheck)); + } + else if(sElem == "chbx_perm_assoc_check") + { + SetLocalInt(oModule, AI_RULE_PERM_ASSOC, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PERM_ASSOC, JsonInt(bCheck)); + } + else if(sElem == "chbx_corpses_stay_check") + { + SetLocalInt(oModule, AI_RULE_CORPSES_STAY, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_CORPSES_STAY, JsonInt(bCheck)); + } + else if(sElem == "chbx_wander_check") + { + SetLocalInt(oModule, AI_RULE_WANDER, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_CORPSES_STAY, JsonInt(bCheck)); + } + else if(sElem == "chbx_open_doors_check") + { + SetLocalInt(oModule, AI_RULE_OPEN_DOORS, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_OPEN_DOORS, JsonInt(bCheck)); + } + else if(sElem == "chbx_party_scale_check") + { + if(bCheck) + { + SetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP, GetModuleXPScale()); + ai_CheckXPPartyScale(oDM); + } + else + { + SetModuleXPScale(GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE)); + } + SetLocalInt(oModule, AI_RULE_PARTY_SCALE, bCheck); + jRules = JsonObjectSet(jRules, AI_RULE_PARTY_SCALE, JsonInt(bCheck)); + string sText = IntToString(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP)); + NuiSetBind(oDM, nToken, "chbx_party_scale_tooltip", JsonString(" PEPS adjusts your XP based on party size from (" + sText + ").")); + sText = IntToString(GetModuleXPScale()); + NuiSetBind(oDM, nToken, "txt_xp_scale", JsonString(sText)); + } + else if(sElem == "chbx_darkness_check") + { + if(bCheck) + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_DARKNESS); + jRules = ai_AddRestrictedSpell(jRules, 159); + jRules = ai_AddRestrictedSpell(jRules, SPELLABILITY_AS_DARKNESS); + jRules = ai_AddRestrictedSpell(jRules, 688); // WildShape_Darkness + } + else + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_DARKNESS, FALSE); + jRules = ai_AddRestrictedSpell(jRules, 159, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELLABILITY_AS_DARKNESS, FALSE); + jRules = ai_AddRestrictedSpell(jRules, 688, FALSE); // WildShape_Darkness + } + } + else if(sElem == "chbx_dispels_check") + { + if(bCheck) + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_LESSER_DISPEL); + jRules = ai_AddRestrictedSpell(jRules, SPELL_DISPEL_MAGIC); + jRules = ai_AddRestrictedSpell(jRules, SPELL_GREATER_DISPELLING); + jRules = ai_AddRestrictedSpell(jRules, SPELL_MORDENKAINENS_DISJUNCTION); + } + else + { + jRules = ai_AddRestrictedSpell(jRules, SPELL_LESSER_DISPEL, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_DISPEL_MAGIC, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_GREATER_DISPELLING, FALSE); + jRules = ai_AddRestrictedSpell(jRules, SPELL_MORDENKAINENS_DISJUNCTION, FALSE); + } + } + else if(sElem == "chbx_timestop_check") + { + if(bCheck) jRules = ai_AddRestrictedSpell(jRules, SPELL_TIME_STOP); + else jRules = ai_AddRestrictedSpell(jRules, SPELL_TIME_STOP, FALSE); + } + ai_SetCampaignDbJson("rules", jRules); + } + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + if(nMouseScroll == 1.0) // Scroll up + { + // Follow range is only changed on non-pc's + if(sElem == "lbl_perc_dist") ai_RulePercDistInc(oDM, GetModule(), 1, nToken); + } + else if(nMouseScroll == -1.0) // Scroll down + { + // Follow range is only changed on non-pc's + if(sElem == "lbl_perc_dist") ai_RulePercDistInc(oDM, GetModule(), -1, nToken); + } + } + } + //************************************************************************** + // Plugins events. + if(sWndId == "dmai_plugin_nui") + { + string sName = ai_RemoveIllegalCharacters(GetName(oDM)); + json jPlugins = ai_GetCampaignDbJson("plugins"); + if(sEvent == "click") + { + if(sElem == "btn_load_plugins") + { + string sScript = JsonGetString(NuiGetBind (oDM, nToken, "txt_plugin")); + if(JsonGetType(JsonArrayGet(jPlugins, 0)) == JSON_TYPE_NULL) jPlugins = JsonArray(); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_buffing"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_forcerest"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_henchmen"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_crafting"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_mod_set"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_debug"); + jPlugins = ai_Plugin_Add(oDM, jPlugins, "pi_test"); + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + if(sElem == "btn_check_plugins") + { + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(TRUE)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + if(sElem == "btn_clear_plugins") + { + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(FALSE)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + else if(sElem == "btn_add_plugin") + { + string sScript = JsonGetString(NuiGetBind (oDM, nToken, "txt_plugin")); + if(JsonGetType(JsonArrayGet(jPlugins, 0)) == JSON_TYPE_NULL) jPlugins = JsonArray(); + jPlugins = ai_Plugin_Add(oDM, jPlugins, sScript); + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + } + else if(GetStringLeft(sElem, 18) == "btn_remove_plugin_") + { + int nIndex = StringToInt(GetStringRight(sElem, 1)); + jPlugins = JsonArrayDel(jPlugins, nIndex); + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMPluginManagerNUI(oDM)); + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oDM, sElem, 2); + } + else if(sEvent == "watch") + { + if(GetStringLeft(sElem, 12) == "chbx_plugin_" && GetStringRight(sElem, 6) == "_check") + { + int nIndex = StringToInt(GetSubString(sElem, 12, 1)); + json jPlugin = JsonArrayGet(jPlugins, nIndex); + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck)); + jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin); + ai_SetCampaignDbJson("plugins", jPlugins); + DelayCommand(0.0, NuiDestroy(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))); + DelayCommand(0.1, ai_CreateDMWidgetNUI(oDM)); + } + } + } + if(sWndId == "dm_widget_manager_nui") + { + //SendMessageToDM(oDM, "sEvent: " + sEvent + " sElem: " + sElem); + if(sEvent == "click") + { + if(sElem == "btn_clear_buttons") + { + object oModule = GetModule(); + SetLocalInt(oModule, sDMWidgetAccessVarname, 0); + SetLocalInt(oModule, sDMAIAccessVarname, 0); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, sDMWidgetAccessVarname, JsonInt(0)); + jRules = JsonObjectSet(jRules, sDMAIAccessVarname, JsonInt(0)); + ai_SetCampaignDbJson("rules", jRules); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMWidgetManagerNUI(oDM)); + return; + } + else if(sElem == "btn_check_buttons") + { + object oModule = GetModule(); + SetLocalInt(oModule, sDMWidgetAccessVarname, 7340028); + SetLocalInt(oModule, sDMAIAccessVarname, 203423743); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, sDMWidgetAccessVarname, JsonInt(7340028)); + jRules = JsonObjectSet(jRules, sDMAIAccessVarname, JsonInt(203423743)); + ai_SetCampaignDbJson("rules", jRules); + DelayCommand(0.0, NuiDestroy(oDM, nToken)); + DelayCommand(0.1, ai_CreateDMWidgetManagerNUI(oDM)); + return; + } + SetLocalInt(oDM, "CHBX_SKIP", TRUE); + DelayCommand(2.0, DeleteLocalInt(oDM, "CHBX_SKIP")); + if(sElem == "btn_cmd_action") NuiSetBind(oDM, nToken, "chbx_cmd_action_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_ACTION))); + else if(sElem == "btn_cmd_guard") NuiSetBind(oDM, nToken, "chbx_cmd_guard_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_GUARD))); + else if(sElem == "btn_cmd_hold") NuiSetBind(oDM, nToken, "chbx_cmd_hold_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_HOLD))); + else if(sElem == "btn_cmd_attack") NuiSetBind(oDM, nToken, "chbx_cmd_attack_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_ATTACK))); + else if(sElem == "btn_cmd_follow") NuiSetBind(oDM, nToken, "chbx_cmd_follow_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_FOLLOW))); + else if(sElem == "btn_follow_target") NuiSetBind(oDM, nToken, "chbx_follow_target_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_FOLLOW_TARGET))); + else if(sElem == "btn_cmd_search") NuiSetBind(oDM, nToken, "chbx_cmd_search_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_SEARCH))); + else if(sElem == "btn_cmd_stealth") NuiSetBind(oDM, nToken, "chbx_cmd_stealth_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_STEALTH))); + else if(sElem == "btn_cmd_ai_script") NuiSetBind(oDM, nToken, "chbx_cmd_ai_script_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_AI_SCRIPT))); + else if(sElem == "btn_cmd_place_trap") NuiSetBind(oDM, nToken, "chbx_cmd_place_trap_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_PLACE_TRAP))); + else if(sElem == "btn_quick_widget") NuiSetBind(oDM, nToken, "chbx_quick_widget_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_SPELL_WIDGET))); + else if(sElem == "btn_spell_memorize") NuiSetBind(oDM, nToken, "chbx_spell_memorize_check", JsonBool(!ai_GetDMWAccessButton(BTN_DM_CMD_MEMORIZE))); + else if(sElem == "btn_buff_short") NuiSetBind(oDM, nToken, "chbx_buff_short_check", JsonBool(!ai_GetDMWAccessButton(BTN_BUFF_SHORT))); + else if(sElem == "btn_buff_long") NuiSetBind(oDM, nToken, "chbx_buff_long_check", JsonBool(!ai_GetDMWAccessButton(BTN_BUFF_LONG))); + else if(sElem == "btn_buff_all") NuiSetBind(oDM, nToken, "chbx_buff_all_check", JsonBool(!ai_GetDMWAccessButton(BTN_BUFF_ALL))); + else if(sElem == "btn_buff_rest") NuiSetBind(oDM, nToken, "chbx_buff_rest_check", JsonBool(!ai_GetDMWAccessButton(BTN_BUFF_REST))); + else if(sElem == "btn_jump_to") NuiSetBind(oDM, nToken, "chbx_jump_to_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_JUMP_TO))); + else if(sElem == "btn_ghost_mode") NuiSetBind(oDM, nToken, "chbx_ghost_mode_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_GHOST_MODE))); + else if(sElem == "btn_camera") NuiSetBind(oDM, nToken, "chbx_camera_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_CAMERA))); + else if(sElem == "btn_inventory") NuiSetBind(oDM, nToken, "chbx_inventory_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_INVENTORY))); + else if(sElem == "btn_familiar") NuiSetBind(oDM, nToken, "chbx_familiar_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_FAMILIAR))); + else if(sElem == "btn_companion") NuiSetBind(oDM, nToken, "chbx_companion_check", JsonBool(!ai_GetDMWAccessButton(BTN_CMD_COMPANION))); + else if(sElem == "btn_ai") NuiSetBind(oDM, nToken, "chbx_ai_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_FOR_PC))); + else if(sElem == "btn_quiet") NuiSetBind(oDM, nToken, "chbx_quiet_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_REDUCE_SPEECH))); + else if(sElem == "btn_ranged") NuiSetBind(oDM, nToken, "chbx_ranged_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_USE_RANGED))); + else if(sElem == "btn_search") NuiSetBind(oDM, nToken, "chbx_search_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_USE_SEARCH))); + else if(sElem == "btn_stealth") NuiSetBind(oDM, nToken, "chbx_stealth_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_USE_STEALTH))); + else if(sElem == "btn_open_door") NuiSetBind(oDM, nToken, "chbx_open_door_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_OPEN_DOORS))); + else if(sElem == "btn_traps") NuiSetBind(oDM, nToken, "chbx_traps_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_REMOVE_TRAPS))); + else if(sElem == "btn_pick_locks") NuiSetBind(oDM, nToken, "chbx_pick_locks_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_PICK_LOCKS))); + else if(sElem == "btn_bash_locks") NuiSetBind(oDM, nToken, "chbx_bash_locks_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_BASH_LOCKS))); + else if(sElem == "btn_magic_level") NuiSetBind(oDM, nToken, "chbx_magic_level_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_MAGIC_LEVEL))); + else if(sElem == "btn_spontaneous") NuiSetBind(oDM, nToken, "chbx_spontaneous_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_NO_SPONTANEOUS))); + else if(sElem == "btn_magic") NuiSetBind(oDM, nToken, "chbx_magic_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_USE))); + else if(sElem == "btn_magic_items") NuiSetBind(oDM, nToken, "chbx_magic_items_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_ITEM_USE))); + else if(sElem == "btn_def_magic") NuiSetBind(oDM, nToken, "chbx_def_magic_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_DEF_MAGIC_USE))); + else if(sElem == "btn_off_magic") NuiSetBind(oDM, nToken, "chbx_off_magic_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_OFF_MAGIC_USE))); + else if(sElem == "btn_heal_out") NuiSetBind(oDM, nToken, "chbx_heal_out_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_HEAL_OUT))); + else if(sElem == "btn_heal_in") NuiSetBind(oDM, nToken, "chbx_heal_in_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_HEAL_IN))); + else if(sElem == "btn_heals_onoff") NuiSetBind(oDM, nToken, "chbx_heals_onoff_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_STOP_SELF_HEALING))); + else if(sElem == "btn_healp_onoff") NuiSetBind(oDM, nToken, "chbx_healp_onoff_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_STOP_PARTY_HEALING))); + else if(sElem == "btn_loot") NuiSetBind(oDM, nToken, "chbx_loot_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_LOOT))); + else if(sElem == "btn_ignore_assoc") NuiSetBind(oDM, nToken, "chbx_ignore_assoc_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_IGNORE_ASSOCIATES))); + else if(sElem == "btn_ignore_traps") NuiSetBind(oDM, nToken, "chbx_ignore_traps_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_IGNORE_TRAPS))); + else if(sElem == "btn_perc_range") NuiSetBind(oDM, nToken, "chbx_perc_range_check", JsonBool(!ai_GetDMAIAccessButton(BTN_AI_PERC_RANGE))); + } + if(sEvent == "watch") + { + if(GetLocalInt(oDM, "CHBX_SKIP")) return; + if(sElem == "chbx_cmd_action_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_ACTION, nToken, sElem); + else if(sElem == "chbx_cmd_guard_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_GUARD, nToken, sElem); + else if(sElem == "chbx_cmd_hold_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_HOLD, nToken, sElem); + else if(sElem == "chbx_cmd_attack_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_ATTACK, nToken, sElem); + else if(sElem == "chbx_cmd_follow_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_FOLLOW, nToken, sElem); + else if(sElem == "chbx_follow_target_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_FOLLOW_TARGET, nToken, sElem); + else if(sElem == "chbx_cmd_search_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_SEARCH, nToken, sElem); + else if(sElem == "chbx_cmd_stealth_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_STEALTH, nToken, sElem); + else if(sElem == "chbx_cmd_ai_script_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_AI_SCRIPT, nToken, sElem); + else if(sElem == "chbx_cmd_place_trap_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_PLACE_TRAP, nToken, sElem); + else if(sElem == "chbx_quick_widget_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_SPELL_WIDGET, nToken, sElem); + else if(sElem == "chbx_spell_memorize_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_DM_CMD_MEMORIZE, nToken, sElem); + else if(sElem == "chbx_buff_short_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_BUFF_SHORT, nToken, sElem); + else if(sElem == "chbx_buff_long_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_BUFF_LONG, nToken, sElem); + else if(sElem == "chbx_buff_all_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_BUFF_ALL, nToken, sElem); + else if(sElem == "chbx_buff_rest_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_BUFF_REST, nToken, sElem); + else if(sElem == "chbx_jump_to_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_JUMP_TO, nToken, sElem); + else if(sElem == "chbx_ghost_mode_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_GHOST_MODE, nToken, sElem); + else if(sElem == "chbx_camera_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_CAMERA, nToken, sElem); + else if(sElem == "chbx_inventory_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_INVENTORY, nToken, sElem); + else if(sElem == "chbx_familiar_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_FAMILIAR, nToken, sElem); + else if(sElem == "chbx_companion_check") ai_SetDMWAccessButtonToCheckbox(oDM, BTN_CMD_COMPANION, nToken, sElem); + else if(sElem == "chbx_ai_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_FOR_PC, nToken, sElem); + else if(sElem == "chbx_quiet_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_REDUCE_SPEECH, nToken, sElem); + else if(sElem == "chbx_ranged_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_USE_RANGED, nToken, sElem); + else if(sElem == "chbx_search_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_USE_SEARCH, nToken, sElem); + else if(sElem == "chbx_stealth_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_USE_STEALTH, nToken, sElem); + else if(sElem == "chbx_open_door_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_OPEN_DOORS, nToken, sElem); + else if(sElem == "chbx_traps_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_REMOVE_TRAPS, nToken, sElem); + else if(sElem == "chbx_pick_locks_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_PICK_LOCKS, nToken, sElem); + else if(sElem == "chbx_bash_locks_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_BASH_LOCKS, nToken, sElem); + else if(sElem == "chbx_magic_level_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_MAGIC_LEVEL, nToken, sElem); + else if(sElem == "chbx_spontaneous_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_NO_SPONTANEOUS, nToken, sElem); + else if(sElem == "chbx_magic_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_NO_MAGIC_USE, nToken, sElem); + else if(sElem == "chbx_magic_items_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_NO_MAGIC_ITEM_USE, nToken, sElem); + else if(sElem == "chbx_def_magic_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_DEF_MAGIC_USE, nToken, sElem); + else if(sElem == "chbx_off_magic_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_OFF_MAGIC_USE, nToken, sElem); + else if(sElem == "chbx_heal_out_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_HEAL_OUT, nToken, sElem); + else if(sElem == "chbx_heal_in_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_HEAL_IN, nToken, sElem); + else if(sElem == "chbx_heals_onoff_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_STOP_SELF_HEALING, nToken, sElem); + else if(sElem == "chbx_healp_onoff_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_STOP_PARTY_HEALING, nToken, sElem); + else if(sElem == "chbx_loot_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_LOOT, nToken, sElem); + else if(sElem == "chbx_ignore_assoc_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_IGNORE_ASSOCIATES, nToken, sElem); + else if(sElem == "chbx_ignore_traps_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_IGNORE_TRAPS, nToken, sElem); + else if(sElem == "chbx_perc_range_check") ai_SetDMAIAccessButtonToCheckbox(oDM, BTN_AI_PERC_RANGE, nToken, sElem); + } + } +} +void ai_SetDMWidgetButtonToCheckbox(object oDM, int nButton, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + ai_SetDMWidgetButton(oDM, nButton, bCheck); +} +void ai_SetDMWAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + ai_SetDMWAccessButton(nButton, bCheck); +} +void ai_SetDMAIAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem) +{ + int bCheck = JsonGetInt(NuiGetBind(oDM, nToken, sElem)); + ai_SetDMAIAccessButton(nButton, bCheck); +} +void ai_RulePercDistInc(object oDM, object oModule, int nIncrement, int nToken) +{ + int nAdjustment = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE) + nIncrement; + if(nAdjustment < 8 || nAdjustment > 11) return; + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, nAdjustment); + string sText; + if(nAdjustment == 8) sText = " Monster perception: Short [10 Sight / 10 Listen]"; + else if(nAdjustment == 9) sText = " Monster perception: Medium [20 Sight / 20 Listen]"; + else if(nAdjustment == 10) sText = " Monster perception: Long [35 Sight / 20 Listen]"; + else sText = " Monster perception: Default [Monster's default values]"; + NuiSetBind(oDM, nToken, "lbl_perc_dist_label", JsonString(sText)); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_MON_PERC_DISTANCE, JsonInt(nAdjustment)); + ai_SetCampaignDbJson("rules", jRules); +} +json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE) +{ + object oModule = GetModule(); + json jRSpells = GetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS); + int nIndex, nMaxIndex = JsonGetLength(jRSpells); + if(bRestrict) + { + while(nIndex < nMaxIndex) + { + if(JsonGetInt(JsonArrayGet(jRSpells, nIndex)) == nSpell) return jRules; + nIndex++; + } + jRSpells = JsonArrayInsert(jRSpells, JsonInt(nSpell)); + } + else + { + while(nIndex < nMaxIndex) + { + if(JsonGetInt(JsonArrayGet(jRSpells, nIndex)) == nSpell) + { + jRSpells = JsonArrayDel(jRSpells, nIndex); + break; + } + nIndex++; + } + } + SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, jRSpells); + return JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, jRSpells); +} +void ai_SelectToGroup(object oDM, string sElem) +{ + string sGroup = GetStringRight(sElem, 1); + SetLocalString(oDM, AI_TARGET_MODE, "DM_SELECT_GROUP" + sGroup); + ai_SendMessages("Select a creature to add to group " + sGroup + ". Selecting yourself will clear group1.", AI_COLOR_YELLOW, oDM); + EnterTargetingMode(oDM, OBJECT_TYPE_CREATURE, MOUSECURSOR_PICKUP, MOUSECURSOR_PICKUP_DOWN); +} +void ai_DMSelectAction(object oDM, string sElem) +{ + string sGroup = GetStringRight(sElem, 1); + SetLocalString(oDM, AI_TARGET_MODE, "DM_ACTION_GROUP" + sGroup); + ai_SendMessages(GetName(oDM) + " select an action for group" + sGroup + ".", AI_COLOR_YELLOW, oDM); + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_DMChangeMoveSpeed(object oDM, string sElem, int nSpeed) +{ + string sGroup = GetStringRight(sElem, 1); + json jGroup = GetLocalJson(oDM, "DM_GROUP" + sGroup); + if(JsonGetType(jGroup) == JSON_TYPE_NULL) + { + ai_SendMessages("This group does not contain any creatures!", AI_COLOR_RED, oDM); + return; + } + jGroup = JsonArraySet(jGroup, 0, JsonInt(nSpeed)); + SetLocalJson(oDM, "DM_GROUP" + sGroup, jGroup); + object oLeader = GetObjectByUUID(JsonGetString(JsonArrayGet(jGroup, 1))); + string sName = GetName(oLeader); + string sText = " " + sName + "'s group"; + if(nSpeed == 0) sText += " [Walk]"; + else sText += " [Run]"; + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText)); + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_COMMAND_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText)); +} diff --git a/src/module/nss/0e_onclientload.nss b/src/module/nss/0e_onclientload.nss new file mode 100644 index 0000000..041d49f --- /dev/null +++ b/src/module/nss/0e_onclientload.nss @@ -0,0 +1,23 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_onclientload + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnClientLoad script; + This will fire when the client is loading. + + If you have your own OnClientLoad event script just take the below + script lines and add them into your OnClientLoad script. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_menus_dm" +#include "0i_module" +void main() +{ + object oCreature = OBJECT_SELF; + // This can be moved to the OnClientLoad script event of your module. + if(ai_GetIsCharacter(oCreature)) ai_CheckPCStart(oCreature); + // If this is a server you can add this as well. + else if(AI_SERVER && (GetIsDM(oCreature) || GetIsPlayerDM(oCreature))) + { + ai_CheckPCStart(oCreature); + } +} diff --git a/src/module/nss/0e_player_target.nss b/src/module/nss/0e_player_target.nss new file mode 100644 index 0000000..16b83fb --- /dev/null +++ b/src/module/nss/0e_player_target.nss @@ -0,0 +1,154 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: 0e_player_target + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + OnPlayerTarget event script + Used to allow player targeting while passing any module player targeting + script through to work as intended. + + We Use a string variable upon the player using the targeting mode to define the + action of the target. + AI_TARGET_MODE is the constant used. + AI_TARGET_ASSOCIATE is the associate that triggered the target mode. +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_player_target" +void main() +{ + object oPC = GetLastPlayerToSelectTarget(); + // Get any plugin target scripts and run it instead of this one. + string sPluginTargetScript = GetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT); + if(sPluginTargetScript != "") + { + DeleteLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT); + ExecuteScript(sPluginTargetScript, oPC); + // Remove the plugin script as it must be set each time the plugin uses the target event. + } + else + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + vector vTarget = GetTargetingModeSelectedPosition(); + location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + object oAssociate = GetLocalObject(oPC, AI_TARGET_ASSOCIATE); + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + // ********************* Exiting Target Actions ************************ + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget) && vTarget == Vector()) + { + if(sTargetMode == "ASSOCIATE_ACTION_ALL") + { + ai_SendMessages("You have exited selecting an action for the party.", AI_COLOR_YELLOW, oPC); + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + if(GetLocalInt(oPC, sGhostModeVarname)) ai_OriginalRemoveAllActionMode(oPC); + } + else ai_RemoveAllActionMode(oPC); + } + else if(sTargetMode == "ASSOCIATE_ACTION") + { + ai_SendMessages("You have exited selecting an action for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC); + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + if(GetLocalInt(oPC, sGhostModeVarname)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + else + { + ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE); + if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && !ai_GetAIMode(oPC, AI_MODE_GHOST) && + GetLocalInt(oAssociate, sGhostModeVarname)) + { + + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + ExecuteScript("nw_ch_ac1", oAssociate); + } + } + else if(sTargetMode == "ASSOCIATE_GET_TRAP") + { + ai_SendMessages(GetName(oAssociate) + " has exited selecing a trap!", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "ASSOCIATE_PLACE_TRAP") + { + ai_SendMessages(GetName(oAssociate) + " has exited placing the trap!", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DM_SELECT_CAMERA_VIEW") + { + AttachCamera(oPC, oPC); + ai_SendMessages(GetName(oPC) + " has defaulted camera view back to the player!", AI_COLOR_YELLOW, oPC); + } + return; + } + // ************************* Targeted Actions ************************** + else + { + // This action makes an associates move to vTarget. + if(sTargetMode == "ASSOCIATE_ACTION_ALL") + { + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + ai_OriginalActionAllAssociates(oPC, oTarget, lLocation); + } + else ai_ActionAllAssociates(oPC, oTarget, lLocation); + } + else if(sTargetMode == "ASSOCIATE_ACTION") + { + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation)); + } + else AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation)); + } + else if(sTargetMode == "ASSOCIATE_FOLLOW_TARGET") ai_SelectFollowTarget(oPC, oAssociate, oTarget); + else if(sTargetMode == "ASSOCIATE_GET_TRAP") ai_SelectTrap(oPC, oAssociate, oTarget); + else if(sTargetMode == "ASSOCIATE_PLACE_TRAP") AssignCommand(oAssociate, ai_PlaceTrap(oPC, lLocation)); + else if(sTargetMode == "ASSOCIATE_USE_ITEM") + { + if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID; + ai_UseWidgetItem(oPC, oAssociate, oTarget, lLocation); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sTargetMode == "ASSOCIATE_USE_FEAT") + { + if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID; + ai_UseWidgetFeat(oPC, oAssociate, oTarget, lLocation); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sTargetMode == "ASSOCIATE_CAST_SPELL") + { + if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID; + ai_CastWidgetSpell(oPC, oAssociate, oTarget, lLocation); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + } + else if(sTargetMode == "DM_SELECT_CAMERA_VIEW") + { + AttachCamera(oPC, oTarget); + ai_SendMessages(GetName(oPC) + " has changed the camera view to " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DM_SELECT_OPEN_INVENTORY") + { + if(LineOfSightObject(oPC, oTarget)) + { + OpenInventory(oTarget, oPC); + ai_SendMessages("You have opened the inventory of "+ GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + } + else ai_SendMessages(GetName(oTarget) + " is not in your line of sight!", AI_COLOR_YELLOW, oPC); + } + else if(GetStringLeft(sTargetMode, 15) == "DM_SELECT_GROUP") + { + ai_AddToGroup(oPC, oTarget, sTargetMode); + } + else if(GetStringLeft(sTargetMode, 15) == "DM_ACTION_GROUP") + { + ai_DMAction(oPC, oTarget, lLocation, sTargetMode); + } + // Get saved module player target script and execute it for pass through compatibility. + string sModuleTargetScript = GetLocalString(GetModule(), AI_MODULE_TARGET_EVENT); + ExecuteScript(sModuleTargetScript); + } + } +} diff --git a/src/module/nss/0e_prc_ch_events.nss b/src/module/nss/0e_prc_ch_events.nss new file mode 100644 index 0000000..3028e9c --- /dev/null +++ b/src/module/nss/0e_prc_ch_events.nss @@ -0,0 +1,78 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0e_prc_ch_events +//////////////////////////////////////////////////////////////////////////////// + associate event handler while using the PRC. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +#include "x0_i0_assoc" +void main() +{ + object oCreature = OBJECT_SELF; + int nEvent = GetCurrentlyRunningEvent(); + //WriteTimestampedLogEntry("0e_prc_ch_events [13] " + GetName(oCreature) + " nEvent: " + IntToString(nEvent)); + switch (nEvent) + { + case EVENT_SCRIPT_CREATURE_ON_HEARTBEAT: + { + if(GetLocalInt(oCreature, "CohortID")) ExecuteScript("prc_ai_coh_hb"); + ExecuteScript("nw_ch_ac1", oCreature); + ExecuteScript("prc_npc_hb", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_NOTICE: + { + ExecuteScript("nw_ch_ac2", oCreature); + ExecuteScript("prc_npc_percep", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DIALOGUE: + { + //if(GetLocalInt(oCreature, "CohortID")) ExecuteScript("prc_ai_coh_conv"); + ExecuteScript("nw_ch_ac4", oCreature); + //ExecuteScript("prc_npc_conv", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED: + { + ExecuteScript("nw_ch_ac5", oCreature); + ExecuteScript("prc_npc_physatt", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DAMAGED: + { + ExecuteScript("nw_ch_ac6", oCreature); + ExecuteScript("prc_npc_damaged", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT: + { + ExecuteScript("nw_ch_acb", oCreature); + ExecuteScript("prc_npc_spellat", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND: + { + ExecuteScript("nw_ch_ac3", oCreature); + ExecuteScript("prc_npc_combat", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR: + { + ExecuteScript("nw_ch_ace", oCreature); + ExecuteScript("prc_npc_blocked", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_RESTED: + { + ExecuteScript("nw_ch_aca", oCreature); + //ExecuteScript("prc_npc_rested", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DISTURBED: + { + ExecuteScript("nw_ch_ac8", oCreature); + ExecuteScript("prc_npc_disturb", oCreature); + break; + } + } +} diff --git a/src/module/nss/0i_actions.nss b/src/module/nss/0i_actions.nss new file mode 100644 index 0000000..7d7d2d7 --- /dev/null +++ b/src/module/nss/0i_actions.nss @@ -0,0 +1,2325 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_actions +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts for action in and out of combat. + + Detect Mode: + Passive(default) mode + * Trap detection radius: 5ft + * Trap detection rate: every 6 seconds + * Trap detection roll: d20 + 1/2 skill + * Spot/Listen roll: d10 + 1/2 skill + + Active(Detect) mode + * Trap detection radius: 10ft + * Trap detection rate: every 3 seconds + * Trap detection roll: d20 + skill + * Spot/Listen roll: d20 + skill + + Stealth checks + * Player detects stealth: 5 times per second. + * Player rolls for hide/move silently & spot/listen: every 6 seconds. + * NPC detects stealth: 4 seconds + * NPC rolls for hide/move silently & spot/listen: every 6 seconds. + + Listen/Move Silently: + * Cannot detect silenced creatures. + * Cannot detect sanctuaried creatures. + * Can only detect invisible (or when your blind) creatures within max attack range. + * Listen checks are made each round for success and failur. + * Outdoors: Objects between you and the target gives a +5 DC for every 40cm of thickness. + * Indoors: No Line of sight and the target is within 40 meters gives a +2 DC. + * +10 DC in combat for the target. + * +5 DC if the target is standing still. + * -5 DC if the listener is standing still. + * +1 DC for every 3 meters of distance to the target. + * Relative size modifiers for both: Tiny +8, Small +4, Medium 0, Larget -4, Huge -8. + * Favored enemy bonuses. + + Spot/Hide: + * Cannot spot invisible creatures. + * Cannot spot any creatures while blinded. + * Night time: Spotter has not light or darkvision +5 DC. + * Night time: Target has a light no them -10 DC. + * +5 DC if target is behind the spotter. + * +10 DC if the spotter are in combat. + * +5 DC if the target is standing still. + * -5 DC if the spotter is standing still. + * Relative size modifiers for both: Tiny +8, Small +4, Medium 0, Larget -4, Huge -8. + * Favored enemy bonuses. + +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_talents" +#include "x0_inc_henai" +#include "X0_I0_ANIMS" +// Chooses an action in combat and executes it for oCreature that is an associate. +void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID); +// Sets variables and states for oAssociate to start combat. +void ai_StartAssociateCombat(object oAssociate, object oTarget = OBJECT_INVALID); +// Chooses an action in combat and executes it for oCreature that is a monster. +void ai_DoMonsterCombatRound(object oCreature); +// Sets variables and states for oMonster to start combat. +void ai_StartMonsterCombat(object oMonster); +// Return the distance that is set for how close we should follow our master. +float ai_GetFollowDistance(object oCreature); +// Returns TRUE if the caller's distance is greater than fDistance from who they +// are following. Unless they are cowardly or in stand ground mode. +// This will also force the caller to move towards them. +int ai_StayClose(object oCreature); +// Returns TRUE if oCreature becomes invisible or hides. +int ai_TryToBecomeInvisible(object oCreature); +// Returns TRUE if oCreature continues to bash a door. +int ai_BashDoorCheck(object oCreature); +// Returns TRUE if we find an hidden creature within battle and do an action. +// If oCreature is too far away they will run upto 14 meters of the invisible creature. +// If oCreature is close they will attempt to cast a spell or search for them. +// bMonster needs to be set for monsters otherwise we do associate perception checks. +// fRange is how close we want to get to hidden targets. +int ai_SearchForHiddenCreature(object oCreature, int bMonster, object oHidden = OBJECT_INVALID, float fRange = 1.0); +// Returns TRUE if oCreature fails a moral check. +// We only make moral checks once we are below AI_HEALTH_WOUNDED health percent. +// If we are at AI_HEALTH_BLOODY hp percent then add + AI_MORAL_INC_DC to the Check. +int ai_MoralCheck(object oCreature); +// Returns TRUE if oCreature is in and nSpell is a dangerous Area Of Effect. +// Used in the on spell cast at scripts. [nw_c2_defaultb and nw_ch_acb]. +int ai_GetInAOEReaction(object oCreature, object oCaster, int nSpell); +// Have the associate speak a random voice from VOICE_CHAT_*. +// nRoll is the number to roll. If nRoll is 0 then it will SpeakString(sVoiceChatArray); +// sVoiceChatArray is an array of VOICE_CHAT_* numbers over nRoll. +// example(4, ":3:4:8:7:") will roll a d4() picking from 3,4,8,7 of VOICE_CHAT_*. +// if nRoll is higher than the number of VOICE_CHAT_* then it will not speak. +void ai_HaveCreatureSpeak(object oCreature, int nRoll, string sVoiceChatArray, int bImportant = FALSE); +// Returns if a spell talent was used. +// This is a common set of AI scripts ran on associate spell casters. +int ai_CheckForAssociateSpellTalent(object oAssociate, int nInMelee, int nMaxLevel, int nRound = 0); +// Targets the best creature oCreature it can see. +// This checks all physcal attack talents starting with ranged attacks then melee. +// Using TALENT_CATEGORY_HARMFUL_MELEE [22] talents. +// If no talents are used it will do either a ranged attack or a melee attack. +void ai_DoPhysicalAttackOnBest(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Targets the nearest creature oCreature it can see. +// This checks all physcal attack talents starting with ranged attacks then melee. +// Using TALENT_CATEGORY_HARMFUL_MELEE [22] talents. +// If no talents are used it will do either a ranged attack or a melee attack. +void ai_DoPhysicalAttackOnNearest(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Targets the weakest creature oCreature can see. +// This checks all physcal attack talents starting with ranged attacks then melee. +// Using TALENT_CATEGORY_HARMFUL_MELEE [22] talents. +// If no talents are used it will do either a ranged attack or a melee attack. +void ai_DoPhysicalAttackOnLowestCR(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Returns TRUE if they equip a melee weapon, FALSE if they don't. +// This also calls for the next combat round. +int ai_InCombatEquipBestMeleeWeapon(object oCreature); +// Returns TRUE if they equip a ranged weapon, FALSE if they don't. +// This also calls for the next combat round. +int ai_InCombatEquipBestRangedWeapon(object oCreature); +// Action wrapper for ai_TryHealing. +void ai_ActionTryHealing(object oCreature, object oTarget); +// Returns TRUE if oCreature heals oTarget. +// This uses an action and must use AssignCommand or OBJECT_SELF is the caster! +int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE); +// oCreature will move into the area looking for creatures. +void ai_ScoutAhead(object oCreature); +// Have oCreature search one object, may continue from that object. +void ai_SearchObject(object oCreature, object oObject, object oMaster, int bOnce = FALSE); +// Returns TRUE if oCreature disarms oTrap. +// bForce if TRUE, oCreature will try to disarm the trap even if they have tried before. +int ai_ReactToTrap(object oCreature, object oTrap, int bForce = FALSE); +// Returns TRUE if oCreature opens oLocked object. +// This will make oCreature open oLocked either by picking or casting a spell. +// bForce if TRUE, oCreature will try to pick the lock even if they have tried before. +int ai_AttemptToByPassLock(object oCreature, object oLocked, int bForce = FALSE); +// Returns TRUE if oCreature opens oDoor. +// bForce if TRUE, oCreature will try to open the door even if they have tried before. +int ai_AttemptToOpenDoor(object oCreature, object oDoor, int bForce = FALSE); +// Action for Checking nearby objects for traps, locks and loot. +void ai_ActionCheckNearbyObjects(object oCreature); +// oCreature will check nearby objects and see what they should do based upon +// selected actions by the player. +int ai_CheckNearbyObjects(object oCreature); +// Used to determine special behaviors for oCeature. +void ai_DetermineSpecialBehavior(object oCreature); +// The target object flees to the specified way point and then destroys itself, +// to be respawned at a later point. For unkillable sign post characters +// who are not meant to fight back. +void ai_ActivateFleeToExit(object oCreature); +// Returns TRUE if oCreature should flee to an exit. +int ai_GetFleeToExit(object oCreature); +// Does random animation in a close distance for creatures. +void ai_AmbientAnimations(); + +void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID) +{ + if(ai_StayClose(oCreature)) return; + // Is the target our Player has locked in dead? If so then clear it. + if(GetIsDead(GetLocalObject(oCreature, AI_PC_LOCKED_TARGET))) DeleteLocalObject(oCreature, AI_PC_LOCKED_TARGET); + // Setup the combat state for this round of combat. + object oNearestEnemy = ai_SetCombatState(oCreature); + // If we are in standground mode we only fight if the enemy is near us. + if(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND) && + ai_GetEnemyAttackingMe(oCreature) == OBJECT_INVALID) oNearestEnemy = OBJECT_INVALID; + // If we found an Enemy or we have a Target then continue into the combat round. + if(oNearestEnemy != OBJECT_INVALID || oTarget != OBJECT_INVALID) + { + // In combat we should stop searching. + if(GetActionMode(oCreature, ACTION_MODE_DETECT) && !GetHasFeat(FEAT_KEEN_SENSE)) + { + SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + } + ai_SetCombatRound(oCreature); + string sAI = GetLocalString(oCreature, AI_COMBAT_SCRIPT); + if(AI_DEBUG) ai_Debug("0i_actions", "167", " AI not Coward/Peaceful: " + + IntToString(sAI != "ai_coward" && sAI != "ai_a_peaceful")); + // If we are using a normal AI script and are polymorphed we should use + // the polymorph AI script. + if(sAI != "ai_coward" && sAI != "ai_a_peaceful") + { + if(AI_DEBUG) ai_Debug("0i_actions", "173", "Should we use polymorph? " + + IntToString(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature))); + if(AI_DEBUG) + { + if(ai_GetIsHidden(oCreature)) + { + ai_Debug("0i_actions", "179", "We are hidden!" + + " Can they see us? " + IntToString(ai_GetNearestIndexThatSeesUs(oCreature))); + } + } + if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature)) + { + sAI = "ai_a_polymorphed"; + } + else if(ai_GetIsHidden(oCreature) && !ai_GetNearestIndexThatSeesUs(oCreature)) sAI = "ai_a_invisible"; + } + if(sAI == "") sAI = "ai_a_default"; + if(AI_DEBUG) ai_Debug("0i_actions", "190", "********** " + GetName (oCreature) + " **********"); + if(AI_DEBUG) ai_Debug("0i_actions", "191", "********** " + sAI + " **********"); + ai_ClearCreatureActions(); + if(AI_DEBUG) ai_Counter_Start(); + // Execute this creatures AI routine. + ExecuteScript(sAI, oCreature); + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + " has finalized round action."); + return; + } + // We have exhausted our check for an enemy. Combat is over. + if(AI_DEBUG) ai_Debug("0i_actions", "200", "---------- " + GetName (OBJECT_SELF) + "'s combat has ended! ----------"); + ai_ClearCombatState(oCreature); + // Run the heartbeat script so we start doing our actions out of combat. + ExecuteScript("nw_ch_ac1", oCreature); +} +void ai_StartAssociateCombat(object oAssociate, object oTarget = OBJECT_INVALID) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "217", "---------- " + GetName(oAssociate) + " is starting combat! ----------"); + ai_SetCreatureTalents(oAssociate, FALSE); + ai_CheckXPPartyScale(oAssociate); + ai_DoAssociateCombatRound(oAssociate, oTarget); +} +void ai_DoMonsterCombatRound(object oMonster) +{ + object oNearestEnemy = ai_SetCombatState(oMonster); + if(oNearestEnemy != OBJECT_INVALID) + { + if(GetActionMode(oMonster, ACTION_MODE_DETECT) && !GetHasFeat(FEAT_KEEN_SENSE, oMonster)) + SetActionMode(oMonster, ACTION_MODE_DETECT, FALSE); + ai_SetCombatRound(oMonster); + string sAI = GetLocalString(oMonster, AI_COMBAT_SCRIPT); + if(sAI != "ai_coward") + { + if(GetAppearanceType(oMonster) != ai_GetNormalAppearance(oMonster)) + { + sAI = "ai_polymorphed"; + } + else if(ai_GetIsHidden(oMonster) && !ai_GetNearestIndexThatSeesUs(oMonster)) sAI = "ai_invisible"; + } + if(sAI == "") sAI = "ai_default"; + if(AI_DEBUG) ai_Debug("0i_actions", "230", "********** " + GetName (oMonster) + " **********"); + if(AI_DEBUG) ai_Debug("0i_actions", "231", "********** " + sAI + " **********"); + // We clear actions here and setup multiple actions to the queue for oCreature. + ai_ClearCreatureActions(); + ai_Counter_Start(); + ExecuteScript(sAI, oMonster); + ai_Counter_End(GetName(oMonster) + " is ending round calculations."); + return; + } + // Check to see if we just didn't see the enemies. + if(GetLocalInt(oMonster, AI_ENEMY_NUMBERS) && + ai_SearchForHiddenCreature(oMonster, TRUE)) return; + // We have exhausted our check for an enemy. Combat is over. + ai_EndCombatRound(oMonster); + ai_ClearCombatState(oMonster); + // Run the heartbeat script so we start doing our actions out of combat. + ExecuteScript("nw_c2_default1", oMonster); + if(AI_DEBUG) ai_Debug("0i_actions", "247", GetName(oMonster) + "'s combat has ended!"); + return; +} +void ai_StartMonsterCombat(object oMonster) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "264", "---------- " + GetName(oMonster) + " is starting combat! ----------"); + ai_SetCreatureTalents(oMonster, TRUE); + ai_DoMonsterCombatRound(oMonster); +} +float ai_GetFollowDistance(object oCreature) +{ + // Also check for size of creature and adjust based on that. + float fDistance = StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oCreature))); + return GetLocalFloat(oCreature, AI_FOLLOW_RANGE) + fDistance; +} +int ai_StayClose(object oCreature) +{ + if(ai_GetIsCharacter(oCreature) || + ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND) || + GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_a_peaceful" || + GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_coward") return FALSE; + object oMaster = GetMaster(oCreature); + // We stay within our perception range of who we are following. + float fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fPerceptionDistance == 0.0) + { + fPerceptionDistance = GetLocalFloat(oMaster, AI_ASSOC_PERCEPTION_DISTANCE); + if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0; + } + object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oMaster; + if(AI_DEBUG) ai_Debug("0i_associates", "214", "Distance from who we are following in combat." + + " oFollowing: " + FloatToString(GetDistanceBetween(oTarget, oCreature), 0, 2) + " fPerceptionDistance: " + FloatToString(fPerceptionDistance, 0, 2)); + if(GetDistanceBetween(oTarget, oCreature) < fPerceptionDistance) return FALSE; + ai_ClearCreatureActions(); + if(AI_DEBUG) ai_Debug("0i_associates", "218", "We are too far away! Move back to our master."); + ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oCreature)); + return TRUE; +} +int ai_TryToBecomeInvisible(object oCreature) +{ + // If we are invisible then we don't need to check this. + if(!ai_GetIsHidden(oCreature)) return FALSE; + // If we are not invisible lets try. + int nDarkness; + if(GetHasSpell(SPELL_DARKNESS, oCreature) && ai_GetHasEffectType(oCreature, EFFECT_TYPE_ULTRAVISION)) nDarkness = TRUE; + if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oCreature) || GetHasSpell(SPELL_INVISIBILITY, oCreature) || + GetHasSpell(SPELL_INVISIBILITY_SPHERE, oCreature) ||(nDarkness) || + GetHasSpell(SPELL_SANCTUARY, oCreature) || GetHasSpell(SPELL_ETHEREALNESS, oCreature) || + GetHasSpell(799/*SPELLABILITY_VAMPIRE_INVISIBILITY*/) || + GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oCreature) == TRUE) + { + // This bit ported directly from Jasperre + // Can anyone see me?(has spell effects of X) + // The point of this is to see if its even worthwhile to go invisbile + // or will it be immediately dispeled. + object oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oCreature, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_TRUE_SEEING); + if(oSeeMe == OBJECT_INVALID) + { + oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oCreature, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_SEE_INVISIBILITY); + } + if(oSeeMe == OBJECT_INVALID) + { + // Check non-invisibility options first. Since they can be used + // while near enemies. + if(GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oCreature)) + { + // Go into stealth mode + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + if(AI_DEBUG) ai_Debug("0i_actions", "207", "Using HIDE_IN_PLAIN_SIGHT!"); + return TRUE; + } + if(nDarkness) + { + ai_SetLastAction(oCreature, SPELL_DARKVISION); + ActionCastSpellAtObject(SPELL_DARKVISION, oCreature); + return TRUE; + } + if(GetHasSpell(SPELL_ETHEREALNESS, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_ETHEREALNESS); + ActionCastSpellAtObject(SPELL_ETHEREALNESS, oCreature); + return TRUE; + } + if(GetHasSpell(SPELL_SANCTUARY, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_SANCTUARY); + ActionCastSpellAtObject(SPELL_SANCTUARY, oCreature); + return TRUE; + } + // Get the nearest Enemy and how close they are. + // Use this to keep invisibility from being spammed in melee. + object oEnemy = ai_GetNearestEnemy(oCreature); + if(GetDistanceBetween(oCreature, oEnemy) > AI_RANGE_MELEE) + { + if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_IMPROVED_INVISIBILITY); + ActionCastSpellAtObject(SPELL_IMPROVED_INVISIBILITY, oCreature); + return TRUE; + } + if(GetHasSpell(SPELL_INVISIBILITY, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_INVISIBILITY); + ActionCastSpellAtObject(SPELL_INVISIBILITY, oCreature); + return TRUE; + } + if(GetHasSpell(SPELL_INVISIBILITY_SPHERE, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_INVISIBILITY_SPHERE); + ActionCastSpellAtObject(SPELL_INVISIBILITY_SPHERE, oCreature); + return TRUE; + } + if(GetHasSpell(799/*SPELLABILITY_VAMPIRE_INVISIBILITY*/, oCreature)) + { + ai_SetLastAction(oCreature, 799/*SPELLABILITY_VAMPIRE_INVISIBILITY*/); + ActionCastSpellAtObject(799/*SPELLABILITY_VAMPIRE_INVISIBILITY*/, oCreature); + return TRUE; + } + } + } + } + return FALSE; +} +int ai_SearchForHiddenCreature(object oCreature, int bMonster, object oInvisible = OBJECT_INVALID, float fRange = 1.0) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "358", GetName(oCreature) + " is searching for an invisible creature (" + + GetName(oInvisible) + ")."); + if(oInvisible == OBJECT_INVALID) + { + // Have we seen anyone go invisible? + oInvisible = GetLocalObject(oCreature, AI_IS_INVISIBLE); + if(oInvisible == OBJECT_INVALID || GetIsDead(oInvisible)) + { + oInvisible = ai_GetNearestEnemy(oCreature, 1, 7, PERCEPTION_HEARD_AND_NOT_SEEN); + if(oInvisible == OBJECT_INVALID) oInvisible = ai_GetNearestEnemy(oCreature); + } + } + float fPerceptionDistance, fDistance; + if(bMonster) + { + GetDistanceBetween(oCreature, oInvisible); + fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE); + } + else + { + // We want to use the distance between the PC and target not us. + object oMaster = GetMaster(); + if(oMaster != OBJECT_INVALID) fDistance = GetDistanceBetween(oMaster, oInvisible); + else GetDistanceBetween(oCreature, oInvisible); + fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0; + } + if(AI_DEBUG) ai_Debug("0i_actions", "383", "Is invisible: " + GetName(oInvisible) + + " fDistance: " + FloatToString(fDistance, 0, 2) + + " fPerceptionDistance: " + FloatToString(fPerceptionDistance, 0, 2)); + // Might need to end combat at this point? + if(fDistance > fPerceptionDistance) return FALSE; + // If we are close enough then lets look for them. + if(fDistance < AI_RANGE_LONG) + { + // nHidden 1 = Invisible effects, 2 = Darkness effects, 3 = Sanctuary effects, 4 Stealth. + int nHidden = ai_GetIsHidden(oInvisible); + if(nHidden) + { + // They have a magical effect! Is there a spell we can use to see? + if(nHidden < 4) + { + if(AI_DEBUG) ai_Debug("0i_actions", "399", " They are using magic to hide: " + + IntToString(nHidden)); + // True Seeing pierces all types of magical hiding. + if(GetHasSpell(SPELL_TRUE_SEEING, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_TRUE_SEEING); + ActionCastSpellAtObject(SPELL_TRUE_SEEING, oCreature); + return TRUE; + } + if(nHidden == 1 || nHidden == 3) // Invisibility or Ethereal effect. + { + if(GetHasSpell(SPELL_SEE_INVISIBILITY, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_SEE_INVISIBILITY); + ActionCastSpellAtObject(SPELL_SEE_INVISIBILITY, oCreature); + return TRUE; + } + if(GetHasSpell(SPELL_INVISIBILITY_PURGE, oCreature)) + { + ai_SetLastAction(oCreature, SPELL_INVISIBILITY_PURGE); + ActionCastSpellAtObject(SPELL_INVISIBILITY_PURGE, oCreature); + return TRUE; + } + } + if(nHidden == 2) // Darkness spell effect. + { + if(GetHasSpell(SPELL_DARKVISION)) + { + ai_SetLastAction(oCreature, SPELL_DARKVISION); + ActionCastSpellAtObject(SPELL_DARKVISION, oCreature); + return TRUE; + } + } + // To be able to attack a magically hidden foe we have to be + // with in melee attack range. Cannot hear Ethereal foes! + // We will automatically hear them once we are within range. + // We also walk so we don't give attacks of opportunity. + if(nHidden < 3) + { + if(AI_DEBUG) ai_Debug("0i_actions", "437", " We have no spells to counter with. Moving up to attack!"); + SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE); + ActionMoveToObject(oInvisible); + ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)); + if(ai_GetIsInCombat(oCreature)) ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + } + else // They are using stealth! + { + if(AI_DEBUG) ai_Debug("0i_actions", "447", " Using Detect mode and moving up."); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE); + // We use to move to the object but that is creepy! + //ActionMoveToObject(oInvisible, FALSE, fRange); + ActionMoveToLocation(GetLocation(oInvisible), FALSE); + ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)); + if(ai_GetIsInCombat(oCreature)) ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + } + else // They are not hidden, then that means we can hear them but not see them. + // Probably behind a wall or door. + { + SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE); + // We use to move to the object but that is creepy! + //ActionMoveToObject(oInvisible, FALSE, fRange); + ActionMoveToLocation(GetLocation(oInvisible), FALSE); + ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)); + if(ai_GetIsInCombat(oCreature)) ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + } + else // We need to get closer to start looking for them. + { + if(AI_DEBUG) ai_Debug("0i_actions", "469", "Moving towards invisible creature from a distance: " + GetName(oInvisible)); + SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE); + // We use to move to the object but that is creepy! + //ActionMoveToObject(oInvisible, TRUE, 14.0); + ActionMoveToLocation(GetLocation(oInvisible), FALSE); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING))); + if(ai_GetIsInCombat(oCreature)) ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + return FALSE; +} +int ai_MoralCheck(object oCreature) +{ + // If we are immune to fear then we are immune to MoralChecks! + // Constructs and Undead are also immune to fear. + int nRaceType = GetRacialType(oCreature); + if(!GetLocalInt(GetModule(), AI_RULE_MORAL_CHECKS) || GetIsImmune(oCreature, IMMUNITY_TYPE_FEAR) || + nRaceType == RACIAL_TYPE_UNDEAD || + nRaceType == RACIAL_TYPE_CONSTRUCT || + ai_GetIsCharacter(oCreature)) return FALSE; + // Moral DC is AI_WOUNDED_MORAL_DC - The number of allies. + // or AI_BLOODY_MORAL_DC - number of allies. + int nDC; + int nHpPercent = ai_GetPercHPLoss(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + // We only make moral checks if we are below half hitpoints and the Difficulty should be adjusted to -10 at 0. + if(nHpPercent <= AI_HEALTH_WOUNDED) + { + // Debug code to look for multiple moral checks at once by one creature? + if(GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) == "") + { + SetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE, GetName(oCreature)); + ai_Debug("0i_actions", "424", GetName(oCreature) + " starting debug mode to test Moral checks!"); + } + if(nHpPercent <= AI_HEALTH_BLOODY) nDC = AI_BLOODY_MORAL_DC; + else nDC = AI_WOUNDED_MORAL_DC; + nDC = nDC - GetLocalInt(oCreature, AI_ALLY_NUMBERS); + if(nDC < 1) nDC = 1; + if(AI_DEBUG) ai_Debug("0i_talents", "367", "Moral check DC: " + IntToString(nDC) + "."); + //SendMessageToPC(GetFirstPC(), "0i_talents, 431, " + GetName(oCreature) + " Moral check DC: " + IntToString(nDC) + "."); + if(!WillSave(oCreature, nDC, SAVING_THROW_TYPE_FEAR, oNearestEnemy)) + { + if(AI_DEBUG) ai_Debug("0i_talents", "370", "Moral check failed, we are fleeing!"); + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_coward"); + effect eVFX = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVFX, oCreature, 6.0f); + ActionMoveAwayFromObject(oNearestEnemy, TRUE, AI_RANGE_LONG); + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + int nRoll = d4(); + if(nRoll == 1) PlayVoiceChat(VOICE_CHAT_FLEE, oCreature); + else if(nRoll == 2) PlayVoiceChat(VOICE_CHAT_GUARDME, oCreature); + else if(nRoll == 3) PlayVoiceChat(VOICE_CHAT_HELP, oCreature); + else if(nRoll == 4 && nHpPercent < 100) PlayVoiceChat(VOICE_CHAT_HEALME, oCreature); + } + return TRUE; + } + if(nDC >= 11 && !ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + int nRoll = d6(); + // Cry out when you are overwhelmed! + if(nRoll == 1) PlayVoiceChat(VOICE_CHAT_CUSS, oCreature); + else if(nRoll == 2) PlayVoiceChat(VOICE_CHAT_BADIDEA, oCreature); + else if(nRoll == 3) PlayVoiceChat(VOICE_CHAT_ENEMIES, oCreature); + } + } + return FALSE; +} +int ai_GetInAOEReaction(object oCreature, object oCaster, int nSpell) +{ + switch(nSpell) + { + case SPELL_ACID_FOG: + case SPELL_CLOUDKILL: + case SPELL_CREEPING_DOOM: + { + // Nothing but bad times with these spells. + return TRUE; + } + case SPELL_STORM_OF_VENGEANCE: + { + // This only harms our enemies! + return (oCaster != oCreature && GetIsEnemy(oCaster, oCreature)); + } + // They should only flee Silence if they want to cast a spell! + //case SPELL_SILENCE: + case SPELL_BLADE_BARRIER: + case SPELL_WALL_OF_FIRE: + case SPELL_INCENDIARY_CLOUD: + { + // Check reflex feats and saves. + return (!GetHasFeat(FEAT_EVASION, oCreature) && + !GetHasFeat(FEAT_IMPROVED_EVASION, oCreature) && + GetReflexSavingThrow(oCreature) < 21 + d6()); + } + case SPELL_STINKING_CLOUD: + { + // Do we have a high fortitude save? 20 + 5 + return (GetFortitudeSavingThrow(oCreature) < 20 + d6()); + } + case SPELL_GREASE: + case SPELL_ENTANGLE: + case SPELL_VINE_MINE_ENTANGLE: + case SPELL_WEB: + { + // Do we have a high reflex save? d20 + 1 + return (!GetHasFeat(FEAT_WOODLAND_STRIDE, oCreature) && + !GetLocalInt(oCreature, "X2_L_IS_INCORPOREAL") && + GetReflexSavingThrow(oCreature) < 15 + d6()); + } + case SPELL_EVARDS_BLACK_TENTACLES: + { + // Small creatures are immune and can they hit me? d20 + 8 + caster lvl(7) + return (GetCreatureSize(oCreature) > 2 && + GetAC(oCreature) < 30 + d6()); + } + case SPELL_CLOUD_OF_BEWILDERMENT: + { + // Do we have a high fortitude save? 20 + 2 + return (GetFortitudeSavingThrow(oCreature) < 17 + d6()); + } + case SPELL_MIND_FOG: + case SPELL_STONEHOLD: + { + // Do we have a high enough will save? 20 + 6 + return (GetWillSavingThrow(oCreature) < 21 + d6()); + } + case SPELL_SPIKE_GROWTH: + case SPELL_VINE_MINE_HAMPER_MOVEMENT: + { + // Do we have a high reflex save? d20 + 3 + return (GetReflexSavingThrow(oCreature) < 18 + d6()); + } + } + return FALSE; +} +void ai_HaveCreatureSpeak(object oCreature, int nRoll, string sVoiceChatArray, int bImportant = FALSE) +{ + if(ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK) && !bImportant) return; + if(nRoll == 0) + { + // Some races shouldn't talk. + int nRacialType = GetRacialType(oCreature); + if(nRacialType == RACIAL_TYPE_ANIMAL || nRacialType == RACIAL_TYPE_BEAST || + nRacialType == RACIAL_TYPE_MAGICAL_BEAST || nRacialType == RACIAL_TYPE_OOZE || + nRacialType == RACIAL_TYPE_UNDEAD || nRacialType == RACIAL_TYPE_VERMIN) return; + SpeakString(sVoiceChatArray); + return; + } + nRoll = Random(nRoll); + string sVoice = ai_GetStringArray(sVoiceChatArray, nRoll); + if(sVoice != "") PlayVoiceChat(StringToInt(sVoice), oCreature); +} +int ai_CheckForAssociateSpellTalent(object oAssociate, int nInMelee, int nMaxLevel, int nRound = 0) +{ + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oAssociate, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return TRUE; + if(ai_UseCreatureTalent(oAssociate, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return TRUE; + } + if(ai_GetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING)) return FALSE; + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oAssociate); + return ai_TryDefensiveTalents(oAssociate, nInMelee, nMaxLevel, nRound, oTarget); +} +void ai_DoPhysicalAttackOnBest(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + talent tUse; + object oTarget; + if(AI_DEBUG) ai_Debug("0i_actions", "496", "Check for ranged attack on nearest enemy!"); + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the nearest targets first. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("0i_actions", "525", "Check for melee attack on nearest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, bAlwaysAtk); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "536", "Do melee attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} +void ai_DoPhysicalAttackOnNearest(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + talent tUse; + object oTarget; + if(AI_DEBUG) ai_Debug("0i_actions", "496", "Check for ranged attack on nearest enemy!"); + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the nearest targets first. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("0i_actions", "525", "Check for melee attack on nearest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee, bAlwaysAtk); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "536", "Do melee attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} +void ai_DoPhysicalAttackOnLowestCR(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "533", "Check for ranged attack on weakest enemy!"); + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the weaker targets. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "559", GetName(OBJECT_SELF) + " does ranged attack on weakest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("0i_actions", "571", "Check for melee attack on weakest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee, bAlwaysAtk); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "577", GetName(OBJECT_SELF) + " does melee attack against weakest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} +int ai_InCombatEquipBestMeleeWeapon(object oCreature) +{ + if(ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature))) return FALSE; + if(ai_EquipBestMeleeWeapon(oCreature)) + { + // We delay 1 second since ActionEquip is not an action we can check for. + // This keeps event scripts from clearing before we actually equip. + SetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS, 2); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + return FALSE; +} +int ai_InCombatEquipBestRangedWeapon(object oCreature) +{ + if(ai_EquipBestRangedWeapon(oCreature)) + { + // We delay 1 second since ActionEquip is not an action we can check for. + // This keeps event scripts from clearing before we actually equip. + SetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS, 1); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + return FALSE; +} +int ai_CheckItemForHealing(object oCreature, object oTarget, object oItem, int nHpLost, int bEquiped = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "629", "Checking Item properties on " + GetName(oItem)); + int nIprpSubType, nSpell, nLevel, nIPType; + itemproperty ipProp = GetFirstItemProperty(oItem); + // Lets skip this if there are no properties. + if(!GetIsItemPropertyValid(ipProp)) return FALSE; + // Check for cast spell property and add them to the talent list. + int nIndex; + ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + if(AI_DEBUG) ai_Debug("0i_actions", "639", "ItempropertyType(15): " + IntToString(GetItemPropertyType(ipProp))); + nIPType = GetItemPropertyType(ipProp); + if(nIPType == ITEM_PROPERTY_CAST_SPELL) + { + nIprpSubType = GetItemPropertySubType(ipProp); + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + if(ai_ShouldWeCastThisCureSpell(nSpell, nHpLost)) + { + // We have established that we can use the item if it is equiped. + if(!bEquiped) ai_CheckIfCanUseItem(oCreature, oItem); + // Get how they use the item (charges or uses per day). + int nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses > 1 && nUses < 7) + { + int nCharges = GetItemCharges(oItem); + if(AI_DEBUG) ai_Debug("0i_actions", "654", "Item charges: " + IntToString(nCharges)); + if(nUses == 6 && nCharges < 1 || nUses == 5 && nCharges < 3 || + nUses == 4 && nCharges < 5 || nUses == 3 && nCharges < 7 || + nUses == 2 && nCharges < 9) return FALSE; + } + else if(nUses > 7 && nUses < 13) + { + int nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(AI_DEBUG) ai_Debug("0i_actions", "662", "Item uses: " + IntToString(nPerDay)); + if(nPerDay == 0) return FALSE; + } + // SubType is the ip spell index for iprp_spells.2da + nIprpSubType = GetItemPropertySubType(ipProp); + if(AI_DEBUG) ai_Debug("0i_actions", "667", GetName(oCreature) + " is using " + GetName(oItem) + " on " + GetName(oTarget) + "."); + ActionUseItemOnObject(oItem, ipProp, oTarget, nIprpSubType); + return TRUE; + } + } + nIndex++; + ipProp = GetNextItemProperty(oItem); + } + return FALSE; +} +int ai_HealSickness(object oCreature, object oTarget, object oPC, int nSickness, int bForce = FALSE) +{ + // If the player is not forcing a check. + if(!bForce) + { + // Is Casting Cure spells off? + if(ai_GetMagicMode(oCreature, AI_MAGIC_CURE_SPELLS_OFF)) return FALSE; + // Do we have no magic on? + if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) return FALSE; + // Should we ignore associates? + if(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + } + // Check for spells. + if(nSickness == AI_ALLY_IS_DISEASED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "717", "Attempting to remove disease."); + if(ai_CheckAndCastSpell(oCreature, SPELL_REMOVE_DISEASE, 0, 0.0, oTarget)) return TRUE; + } + else if(nSickness == AI_ALLY_IS_POISONED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "726", "Attempting to remove poison."); + if(ai_CheckAndCastSpell(oCreature, SPELL_NEUTRALIZE_POISON, 0, 0.0, oTarget)) return TRUE; + } + else if(nSickness == AI_ALLY_IS_WEAK) + { + if(AI_DEBUG) ai_Debug("0i_actions", "735", "Attempting to remove ability score drain."); + if(ai_CheckAndCastSpell(oCreature, SPELL_LESSER_RESTORATION, 0, 0.0, oTarget)) return TRUE; + if(ai_CheckAndCastSpell(oCreature, SPELL_RESTORATION, 0, 0.0, oTarget)) return TRUE; + if(ai_CheckAndCastSpell(oCreature, SPELL_GREATER_RESTORATION, 0, 0.0, oTarget)) return TRUE; + } + else return FALSE; + // Check for healing kits. + if(!GetLocalInt(GetModule(), AI_RULE_HEALERSKITS)) return FALSE; + int nIprpSubType, nSpell; + itemproperty ipProp; + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetIdentified(oItem)) + { + int nBaseItemType = GetBaseItemType(oItem); + if(nBaseItemType == BASE_ITEM_HEALERSKIT && + (nSickness == AI_ALLY_IS_DISEASED || + nSickness == AI_ALLY_IS_POISONED)) + { + ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + if(GetItemPropertyType(ipProp) == ITEM_PROPERTY_HEALERS_KIT) + { + if(AI_DEBUG) ai_Debug("0i_actions", "772", "Attempting to remove (" + IntToString(nSickness) + ") with a healing kit."); + if(ai_GetIsCharacter(oPC)) ai_SendMessages(GetName(oCreature) + " uses " + GetName(oItem) + " on " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + ipProp = GetNextItemProperty(oItem); + } + } + else if(nBaseItemType == BASE_ITEM_POTIONS || + nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == FEAT_BREW_POTION) + { + ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + nIprpSubType = GetItemPropertySubType(ipProp); + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + if(AI_DEBUG) ai_Debug("0i_actions", "789", "Checking potion, " + IntToString(nSpell)); + if(nSpell == SPELL_REMOVE_DISEASE && nSickness == AI_ALLY_IS_DISEASED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "786", "Using a potion of Remove Disease."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_NEUTRALIZE_POISON && nSickness == AI_ALLY_IS_POISONED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "786", "Using a potion of Neturalize Poison."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_LESSER_RESTORATION && nSickness == AI_ALLY_IS_WEAK) + { + if(AI_DEBUG) ai_Debug("0i_actions", "781", "Using a potion of Lesser Restoration."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_RESTORATION && nSickness == AI_ALLY_IS_WEAK) + { + if(AI_DEBUG) ai_Debug("0i_actions", "791", "Using a potion of Restoration."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + ipProp = GetNextItemProperty(oItem); + } + } + else if(nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL || + nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == BASE_ITEM_MAGICSTAFF) + { + if(ai_CheckIfCanUseItem(oCreature, oItem)) + { + ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + if(nSpell == SPELL_REMOVE_DISEASE && nSickness == AI_ALLY_IS_DISEASED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "786", "Using a potion of Remove Disease."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_NEUTRALIZE_POISON && nSickness == AI_ALLY_IS_POISONED) + { + if(AI_DEBUG) ai_Debug("0i_actions", "786", "Using a potion of Neturalize Poison."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_LESSER_RESTORATION && nSickness == AI_ALLY_IS_WEAK) + { + if(AI_DEBUG) ai_Debug("0i_actions", "781", "Using a potion of Lesser Restoration."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + if(nSpell == SPELL_RESTORATION && nSickness == AI_ALLY_IS_WEAK) + { + if(AI_DEBUG) ai_Debug("0i_actions", "791", "Using a potion of Restoration."); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + ipProp = GetNextItemProperty(oItem); + } + } + } + } + oItem = GetNextItemInInventory(oCreature); + } + return FALSE; +} +int ai_UseHealingItem(object oCreature, object oTarget, object oPC) +{ + if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC_ITEMS)) return FALSE; + string sSlots; + int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + itemproperty ipProp; + // Cycle through all the creatures equiped items. + int nSlot; + object oItem = GetItemInSlot(nSlot, oCreature); + while(nSlot < 11) + { + if(oItem != OBJECT_INVALID && + ai_CheckItemForHealing(oCreature, oTarget, oItem, nDamage, TRUE)) return TRUE; + oItem = GetItemInSlot(++nSlot, oCreature); + } + oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetIdentified(oItem)) + { + // Does the item need to be equiped to use its powers? + sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)); + if(AI_DEBUG) ai_Debug("0i_actions", "696", GetName(oItem) + " requires " + Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) + " slots."); + if(sSlots == "0x00000") + { + int nBaseItemType = GetBaseItemType(oItem); + // Lets not use up our healing kits on minor damage. + if(nBaseItemType == BASE_ITEM_HEALERSKIT) + { + if(!GetLocalInt(GetModule(), AI_RULE_HEALERSKITS)) return FALSE; + ipProp = GetFirstItemProperty(oItem); + if(GetItemPropertyType(ipProp) == ITEM_PROPERTY_HEALERS_KIT) + { + if(ai_GetIsCharacter(oPC)) ai_SendMessages(GetName(oCreature) + " uses " + GetName(oItem) + " on " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + ActionUseItemOnObject(oItem, ipProp, oTarget); + return TRUE; + } + } + // Do we want Player AI and Associates to use potions on others? + //else if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + // nBaseItemType == BASE_ITEM_POTIONS) + //{ + // if(oCaster == oTarget) + // { + // if(ai_CheckItemForHealing(oCreature, oTarget, oItem, nDamage)) return TRUE; + // } + //} + else if(ai_CheckItemForHealing(oCreature, oTarget, oItem, nDamage)) return TRUE; + } + } + oItem = GetNextItemInInventory(oCreature); + } + return FALSE; +} +void ai_ActionTryHealing(object oCreature, object oTarget) +{ + ai_TryHealing(oCreature, oTarget, TRUE); +} +int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "733", "Try healing: oCreature: " + GetName(oCreature) + + " oTarget: " + GetName(oTarget) + " No Party Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) + + " No Self Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF)) + + " AI_I_AM_BEING_HEALED: " + IntToString(GetLocalInt(oTarget, "AI_I_AM_BEING_HEALED")) + + " Undead: " + IntToString(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)); + // If the player is not forcing a check. + if(!bForce) + { + // Should we ignore associates? + if(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + } + // Limits the number of times a wounded creature will ask for help. + if(GetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT") > 3) return FALSE; + // This keeps everyone from healing the same character in one round and over healing! + if(oCreature == oTarget) DeleteLocalInt(oTarget, "AI_I_AM_BEING_HEALED"); + else if(GetLocalInt(oTarget, "AI_I_AM_BEING_HEALED")) return FALSE; + if(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF) && + oCreature != oTarget) return FALSE; + if(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF) && + oCreature == oTarget) return FALSE; + // Undead don't heal so lets skip this for them, maybe later we can fix this. + if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) return FALSE; + int nHpLost = ai_GetPercHPLoss(oTarget); + if(bForce && nHpLost < 100) nHpLost = 0; + if(AI_DEBUG) ai_Debug("0i_actions", "743", "nHpLost: " + IntToString(nHpLost) + + " limit: " + IntToString(ai_GetHealersHpLimit(oTarget, FALSE))); + if(nHpLost >= ai_GetHealersHpLimit(oTarget, FALSE)) + { + // Check to see if we need poison, disease, or ability drain removed. + int nEffectType; + effect eEffect = GetFirstEffect(oTarget); + while(GetIsEffectValid(eEffect)) + { + nEffectType = GetEffectType(eEffect); + if(AI_DEBUG) ai_Debug("0i_actions", "1094", "Checking to cure(31/32/39) nEffectType: " + IntToString(nEffectType)); + if(nEffectType == EFFECT_TYPE_DISEASE) + { + if(AI_DEBUG) ai_Debug("0i_actions", "1097", "I am diseased!"); + if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_DISEASED, bForce)) return TRUE; + if(oCreature == oTarget) + { + if(!d20()) ai_HaveCreatureSpeak(oCreature, 5, ":43:4:14:15:16:"); + SpeakString(AI_I_AM_DISEASED, TALKVOLUME_SILENT_TALK); + } + } + else if(nEffectType == EFFECT_TYPE_POISON) + { + if(AI_DEBUG) ai_Debug("0i_actions", "1107", "I am poisoned!"); + if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_POISONED, bForce)) return TRUE; + if(oCreature == oTarget) + { + if(!d20()) ai_HaveCreatureSpeak(oCreature, 6, ":43:4:14:15:16:19:"); + SpeakString(AI_I_AM_POISONED, TALKVOLUME_SILENT_TALK); + } + } + else if(nEffectType == EFFECT_TYPE_ABILITY_DECREASE) + { + if(AI_DEBUG) ai_Debug("0i_actions", "1117", "I am weak!"); + if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_WEAK, bForce)) return TRUE; + if(oCreature == oTarget) + { + if(!d20()) ai_HaveCreatureSpeak(oCreature, 3, ":43:4:5:"); + SpeakString(AI_I_AM_WEAK, TALKVOLUME_SILENT_TALK); + } + } + eEffect = GetNextEffect(oTarget); + } + return FALSE; + } + // Do they have Lay on Hands? + if(GetHasFeat(FEAT_LAY_ON_HANDS, oCreature)) + { + int nCanHeal = GetAbilityModifier(ABILITY_CHARISMA, oCreature) * ai_GetCharacterLevels(oCreature); + if(nCanHeal <= nHpLost) + { + ai_UseFeat(oCreature, FEAT_LAY_ON_HANDS, oTarget); + return TRUE; + } + } + object oMaster = ai_GetPlayerMaster(oCreature); + // Do we have no magic on? + if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) + { + int nClass, nPosition = 1; + string sMemorized; + while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + nClass = GetClassByPosition(nPosition, oCreature); + if(AI_DEBUG) ai_Debug("0i_actions", "753", "nClass: " + IntToString(nClass)); + if(nClass == CLASS_TYPE_INVALID) break; + sMemorized = Get2DAString("classes", "MemorizesSpells", nClass); + // If Memorized column is "" then they are not a caster. + if(sMemorized != "") + { + if(sMemorized == "1") + { + if(ai_CastMemorizedHealing(oCreature, oTarget, oMaster, nClass)) + { + SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE); + return TRUE; + } + } + else if(ai_CastKnownHealing(oCreature, oTarget, oMaster, nClass)) + { + SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE); + return TRUE; + } + } + nPosition++; + } + } + // We have exhausted all attempts to use normal healing spells. + if(ai_UseHealingItem(oCreature, oTarget, oMaster)) + { + SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE); + return TRUE; + } + // Final attempt to heal oTarget, check for Spontaneous cure spells. + if(ai_CastSpontaneousCure(oCreature, oTarget, oMaster)) + { + SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE); + return TRUE; + } + // We can't heal ourselves! Can any of our allies? Lets ask. + if(oCreature == oTarget) + { + SetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT", GetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT") + 1); + SpeakString(AI_I_AM_WOUNDED, TALKVOLUME_SILENT_TALK); + } + return FALSE; +} +int ai_PerceiveEnemy(object oCreature, object oEnemy) +{ + float fDistance = GetDistanceBetween(oCreature, oEnemy); + if(fDistance < 50.0) + { + // Game is in meters, so 1 foot = 3.333 meter + // penalty is -1 per 10' so divide it by 10 to use 0.3333f + int nDC = 10 + FloatToInt(fDistance * 0.3333f); + // Check to see if the creature is hiding and add the creatures checks. + int nEnemyMoveSilent, nEnemyHide; + if(GetStealthMode(oEnemy)) + { + nEnemyMoveSilent =(d20() + GetSkillRank(SKILL_MOVE_SILENTLY, oEnemy)); + nEnemyHide =(d20() + GetSkillRank(SKILL_HIDE, oEnemy)); + } + if(GetIsSkillSuccessful (oCreature, SKILL_SPOT, nDC + nEnemyHide)) return TRUE; + if(GetIsSkillSuccessful (oCreature, SKILL_LISTEN, nDC + nEnemyMoveSilent)) return TRUE; + } + return FALSE; +} +void ai_ScoutAhead(object oCreature) +{ + object oPerceived; + object oEnemy = ai_GetNearestEnemy(oCreature, 1, -1, -1, -1, -1, TRUE); + // We see them so fight! + if(oEnemy != OBJECT_INVALID) + { + if(ai_PerceiveEnemy(oCreature, oEnemy)) + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + int nRoll = d10(); + if(nRoll == 1) PlayVoiceChat(VOICE_CHAT_ENEMIES, oCreature); + else if(nRoll == 2) PlayVoiceChat(VOICE_CHAT_FOLLOWME, oCreature); + else if(nRoll == 3) PlayVoiceChat(VOICE_CHAT_LOOKHERE, oCreature); + } + ActionMoveToObject(oEnemy, TRUE, AI_RANGE_LONG); + return; + } + // There are enemies here so lets go to them. + else + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + int nRoll = d3(); + if(nRoll == 1) PlayVoiceChat(VOICE_CHAT_BADIDEA, oCreature); + else if(nRoll == 2) PlayVoiceChat(VOICE_CHAT_SEARCH, oCreature); + else if(nRoll == 3) PlayVoiceChat(VOICE_CHAT_FOLLOWME, oCreature); + } + ActionMoveToObject(oEnemy, TRUE, AI_RANGE_CLOSE); + } + } + // There are no more enemies, but we must look like we are patroling so + // go to encounter points. + else + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + int nRoll = d10(); + if(nRoll == 1) PlayVoiceChat(VOICE_CHAT_BADIDEA, oCreature); + else if(nRoll == 2) PlayVoiceChat(VOICE_CHAT_SEARCH, oCreature); + else if(nRoll == 3) PlayVoiceChat(VOICE_CHAT_FOLLOWME, oCreature); + } + // No enemy so lets get a spawn point! + object oSpawnPoint = GetNearestObjectByTag("ip_encounter", oCreature, d6()); + ActionMoveToObject(oSpawnPoint, TRUE, AI_RANGE_CLOSE); + } +} +int ai_ShouldIPickItUp(object oCreature, object oItem) +{ + int nMinGold; + if(GetResRef(oItem) == "nw_it_gold001") return TRUE; + int nBaseItem = GetBaseItemType(oItem); + if(GetPlotFlag(oItem)) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_PLOT)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_2"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_ARMOR) + { + if (ai_GetLootFilter(oCreature, AI_LOOT_ARMOR)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_3"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BELT) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_BELTS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_4"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BOOTS) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_BOOTS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_5"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_CLOAK) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_CLOAKS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_6"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_GEM) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_GEMS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_7"); + else return FALSE; + } + else if((nBaseItem == BASE_ITEM_BRACER|| nBaseItem == BASE_ITEM_GLOVES)) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_GLOVES)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_8"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_HELMET) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_HEADGEAR)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_9"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_AMULET || nBaseItem == BASE_ITEM_RING) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_JEWELRY)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_10"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BLANK_POTION || nBaseItem == BASE_ITEM_POTIONS || + nBaseItem == BASE_ITEM_ENCHANTED_POTION) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_POTIONS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_12"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BLANK_SCROLL || nBaseItem == BASE_ITEM_SCROLL || + nBaseItem == BASE_ITEM_ENCHANTED_SCROLL || nBaseItem == BASE_ITEM_SPELLSCROLL) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_SCROLLS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_13"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BLANK_WAND || nBaseItem == BASE_ITEM_ENCHANTED_WAND || + nBaseItem == BASE_ITEM_MAGICWAND || nBaseItem == BASE_ITEM_MAGICROD || + nBaseItem == BASE_ITEM_MAGICSTAFF) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_WANDS_RODS_STAVES)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_15"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_ARROW) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_ARROWS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_17"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BOLT) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_BOLTS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_18"); + else return FALSE; + } + else if(nBaseItem == BASE_ITEM_BULLET) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_BULLETS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_19"); + else return FALSE; + } + else if(ai_GetIsWeapon(oItem)) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_WEAPONS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_16"); + else return FALSE; + } + else if(ai_GetIsShield(oItem)) + { + if(ai_GetLootFilter(oCreature, AI_LOOT_SHIELDS)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_14"); + else return FALSE; + } + else if(ai_GetLootFilter(oCreature, AI_LOOT_MISC)) nMinGold = GetLocalInt(oCreature, "AI_MIN_GOLD_11"); + else return FALSE; + // Check if it is too heavy. + int nItemWeight = GetWeight(oItem); + if(AI_DEBUG) ai_Debug("0i_actions", "1146", GetName(oItem) + " nItemWeight: " + + IntToString(nItemWeight) + " Max Weight: " + IntToString(GetLocalInt(oCreature, AI_MAX_LOOT_WEIGHT) * 10)); + if(nItemWeight > GetLocalInt(oCreature, AI_MAX_LOOT_WEIGHT) * 10) return FALSE; + // Check if it is not valuable enough. + int bID = GetIdentified(oItem); + if(!bID) SetIdentified(oItem, TRUE); + int nItemValue = GetGoldPieceValue(oItem); + if(!bID) SetIdentified(oItem, FALSE); + if(AI_DEBUG) ai_Debug("0i_actions", "998", GetName(oItem) + " nMinGold: " + IntToString(nMinGold) + " nItemValue: " + + IntToString(nItemValue) + " bID: " + IntToString(bID)); + if(nMinGold > nItemValue) return FALSE; + return TRUE; +} +void ai_TakeItemMessage(object oCreature, object oObject, object oItem, object oMaster) +{ + int bId = GetIdentified(oItem); + int nCreatureSkill = GetSkillRank(SKILL_LORE, oCreature); + int nMasterSkill = GetSkillRank(SKILL_LORE, oMaster); + if(nCreatureSkill + nMasterSkill > 0) + { + if(nCreatureSkill > nMasterSkill) ai_IdentifyItemVsKnowledge(oCreature, oItem); + else ai_IdentifyItemVsKnowledge(oMaster, oItem); + } + if(!ai_GetIsCharacter(oCreature)) + { + if(GetIdentified(oItem)) + { + if(bId) ai_SendMessages(GetName(oCreature) + " has found a " + GetName(oItem) + " from the " + GetName(oObject) + ".", AI_COLOR_GRAY, oMaster); + else ai_SendMessages(GetName(oCreature) + " has found and identified " + GetName(oItem) + " from the " + GetName(oObject) + ".", AI_COLOR_GREEN, oMaster); + } + else if(!ai_GetIsCharacter(oCreature)) + { + string sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem)))); + ai_SendMessages(GetName(oCreature) + " has found a " + sBaseName + " from the " + GetName(oObject) + ".", AI_COLOR_GRAY, oMaster); + } + } + else if(GetIdentified(oItem) && !bId) + { + ai_SendMessages(GetName(oCreature) + " has identified " + GetName(oItem) + " from the " + GetName(oObject) + ".", AI_COLOR_GREEN, oMaster); + } + if(GetPlotFlag(oItem)) + { + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) PlayVoiceChat(VOICE_CHAT_LOOKHERE, oCreature); + } +} +void ai_SearchObject(object oCreature, object oObject, object oMaster, int bOnce = FALSE) +{ + ai_Debug("0i_actions", "966", GetName(OBJECT_SELF) + " is opening " + GetName(oObject)); + string sTag = GetTag(oCreature); + AssignCommand(oObject, ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN)); + if(GetIsTrapped(oObject)) DoPlaceableObjectAction(oObject, PLACEABLE_ACTION_USE); + SetLocalInt(oObject, "AI_LOOTED_" + sTag, TRUE); + // Big Hack to allow NPC's to loot! + string sLootScript = GetEventScript(oObject, EVENT_SCRIPT_PLACEABLE_ON_OPEN); + //ai_Debug("0i_actions", "972", "Loot script: " + sLootScript); + if(sLootScript != "") + { + // Used in Original Campaign, and SOU for loot scripts to get treasure to work. + SetLocalObject(oObject, "AI_GET_LAST_OPENED_BY", oMaster); + ExecuteScript(sLootScript, oObject); + } + AssignCommand(oObject, ActionWait(2.0f)); + AssignCommand(oObject, ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE)); + int nItemType, nGold; + object oItem = GetFirstItemInInventory(oObject); + //ai_Debug("0i_actions", "983", "Found: " + GetName(oItem) + " ResRef: " + GetResRef(oItem) + + // " in " + GetName(oObject)); + while(oItem != OBJECT_INVALID) + { + ai_Debug("0i_actions", "987", "Found: " + GetName(oItem) + " ResRef: " + GetResRef(oItem)); + if(ai_ShouldIPickItUp(oCreature, oItem)) + { + ai_Debug("0i_actions", "1002", "Taking: " + GetName(oItem)); + if(GetResRef(oItem) == "nw_it_gold001") + { + if(!ai_GetIsCharacter(oCreature)) + { + int nGold = GetItemStackSize(oItem); + DestroyObject(oItem); + ActionDoCommand(GiveGoldToCreature(oMaster, nGold)); + ActionDoCommand(ai_SendMessages(GetName(oCreature) + " has retrieved " + IntToString(nGold) + + " gold from the " + GetName(oObject) + ".", AI_COLOR_GRAY, oMaster)); + } + else AssignCommand(oCreature, ActionTakeItem(oItem, oObject)); + } + // Check if they are a henchman, companions and familiars give all items to the pc. + else if(!ai_GetLootFilter(oCreature, AI_LOOT_GIVE_TO_PC) && + GetAssociateType(oCreature) == ASSOCIATE_TYPE_HENCHMAN && + !GetPlotFlag(oItem)) + { + if(GetBaseItemFitsInInventory(GetBaseItemType(oItem), oCreature)) + { + ActionDoCommand(ai_TakeItemMessage(oCreature, oObject, oItem, oMaster)); + ActionTakeItem(oItem, oObject); + } + else + { + if(GetIdentified(oItem)) SpeakString("My inventory is full! I cannot pick up the " + GetName(oItem) + "."); + else + { + string sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem)))); + SpeakString("My inventory is full! I cannot pick up the " + sBaseName + "."); + } + } + } + else + { + if(GetBaseItemFitsInInventory(GetBaseItemType(oItem), oMaster)) + { + //ai_Debug("0i_actions", "1010", "Giving to master: " + GetName(oItem)); + ActionDoCommand(ai_TakeItemMessage(oCreature, oObject, oItem, oMaster)); + AssignCommand(oObject, ActionGiveItem(oItem, oMaster)); + } + else + { + if(GetIdentified(oItem)) SpeakString("Your inventory is full! You cannot take the " + GetName(oItem) + "."); + else + { + string sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem)))); + SpeakString("Your inventory is full! You cannot take the " + sBaseName + "."); + } + } + } + } + oItem = GetNextItemInInventory(oObject); + //ai_Debug("0i_actions", "1016", GetName(oItem) + " is the next item."); + } + //ai_Debug("0i_actions", "1018", "Setting object as looted. Check for a new Placeable."); + if(!bOnce) ActionDoCommand(ai_ActionCheckNearbyObjects(oCreature)); +} +int ai_IsContainerLootable(object oCreature, object oObject) +{ + string sTag = GetTag(oCreature); + //ai_Debug("0i_actions", "1303", GetName(oObject) + " (sTag " + GetTag(oObject) + ") " + + // "has inventory: " + IntToString(GetHasInventory(oObject)) + " Has been looted: " + + // IntToString(GetLocalInt(oObject, "AI_LOOTED_" + sTag)) + " Is Useable? " + + // IntToString(GetUseableFlag(oObject))); + if(!GetHasInventory(oObject) || !GetUseableFlag(oObject)) return FALSE; + // This associate has already looted this object, skip. + if(GetLocalInt(oObject, "AI_LOOTED_" + sTag) || ai_GetIsCharacter(oObject)) return FALSE; + return TRUE; +} +int ai_AttempToCastKnockSpell(object oCreature, object oLocked) +{ + if(GetHasSpell(SPELL_KNOCK, oCreature) && + (GetIsDoorActionPossible(oLocked, DOOR_ACTION_KNOCK) || + GetIsPlaceableObjectActionPossible(oLocked, PLACEABLE_ACTION_KNOCK)) && + ai_GetIsInLineOfSight(oCreature, oLocked)) + { + SetLocalInt(oLocked, AI_OBJECT_IN_USE, TRUE); + DelayCommand(6.0, DeleteLocalInt(oLocked, AI_OBJECT_IN_USE)); + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionWait(1.0)); + AssignCommand(oCreature, ActionCastSpellAtObject(SPELL_KNOCK, oLocked)); + AssignCommand(oCreature, ActionWait(1.0)); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oLocked, AI_OBJECT_IN_USE))); + return TRUE; + } + return FALSE; +} +int ai_ReactToTrap(object oCreature, object oTrap, int bForce = FALSE) +{ + int nTrapDC = GetTrapDisarmDC(oTrap); + if(AI_DEBUG) ai_Debug("0i_actions", "1520", "Reacting to trap on " + GetName(oTrap) + + " bForce: " + IntToString(bForce) + " nTrapDC: " + IntToString(nTrapDC) + + " [AI_OBJECT_IN_USE: " + IntToString(GetLocalInt(oTrap, AI_OBJECT_IN_USE)) + "]."); + if(nTrapDC == 0) return FALSE; + string sTag = GetTag(oCreature); + if(bForce || ai_GetAIMode(oCreature, AI_MODE_DISARM_TRAPS)) + { + if(GetTrapDisarmable(oTrap)) + { + if(GetLocalInt(oTrap, AI_OBJECT_IN_USE)) return FALSE; + // We must have ranks in disable traps to actually disable the trap! + if(GetSkillRank(SKILL_DISABLE_TRAP, oCreature, TRUE)) + { + int nSkill = GetSkillRank(SKILL_DISABLE_TRAP, oCreature); + if(AI_DEBUG) ai_Debug("0i_actions", "1534", "nSkill: " + IntToString(nSkill) + + " + 20 = " + IntToString(nSkill + 20) + " nTrapDC: " + IntToString(nTrapDC)); + if(nSkill + 20 >= nTrapDC) + { + SetLocalInt(oTrap, AI_OBJECT_IN_USE, TRUE); + DelayCommand(18.0, DeleteLocalInt(oTrap, AI_OBJECT_IN_USE)); + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionUseSkill(SKILL_DISABLE_TRAP, oTrap, 0)); + // Let them know we did it! + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 6, ":44:42:31:35:"))); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oTrap, AI_OBJECT_IN_USE))); + // Continue checking for traps, locks, and loot. + AssignCommand(oCreature, ActionDoCommand(ai_ActionCheckNearbyObjects(oCreature))); + return TRUE; + } + if(GetHasSpell(SPELL_FIND_TRAPS, oCreature)) + { + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionCastSpellAtObject(SPELL_FIND_TRAPS, oTrap)); + // Continue checking for traps, locks, and loot. + AssignCommand(oCreature, ActionDoCommand(ai_ActionCheckNearbyObjects(oCreature))); + return TRUE; + } + } + if(GetLocalInt(oTrap, "AI_CANNOT_TRAP_" + sTag) && !bForce) return FALSE; + // Let them know we can't get this done!. + //StrRef(40551) "I cannot disarm this trap!" + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, GetStringByStrRef(40551))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oTrap, "AI_CANNOT_TRAP_" + sTag, TRUE); + return FALSE; + } + if(GetLocalInt(oTrap, "AI_SAW_TRAP_" + sTag) && !bForce) return FALSE; + // Let them know we can't get this done!. + ai_HaveCreatureSpeak(oCreature, 0, "I'm not skilled enough to disable the trap!", TRUE); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oTrap, "AI_SAW_TRAP_" + sTag, TRUE); + return FALSE; + } + if(GetObjectType(oTrap) == OBJECT_TYPE_TRIGGER) + { + object oMaster = ai_GetPlayerMaster(oCreature); + if(oMaster != OBJECT_INVALID && !ai_GetIsCharacter(oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_IGNORE_TRAPS)) + { + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, TRUE); + ai_SetAIMode(oCreature, AI_MODE_FOLLOW, FALSE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI); + ai_HighlightWidgetMode(oMaster, oCreature, nToken); + aiSaveAssociateModesToDb(oMaster, oCreature); + if(ai_IsInCombatRound(oCreature)) ai_ClearCombatState(oCreature); + ai_ClearCreatureActions(TRUE); + ai_SendMessages(GetName(oCreature) + " has went into hold mode after seeing a trap!", AI_COLOR_YELLOW, oMaster); + return TRUE; + } + } + if(ai_GetAIMode(oCreature, AI_MODE_PICKUP_ITEMS)) + { + if(GetLocalInt(oTrap, "AI_SAW_TRAP_" + sTag) && !bForce) return FALSE; + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oTrap) + " is trapped!", TRUE)); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oTrap, "AI_SAW_TRAP_" + sTag, TRUE); + } + return FALSE; +} +int ai_AttemptToByPassLock(object oCreature, object oLocked, int bForce = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "1446", "Attempting to bypass lock on " + + GetName(oLocked) + " [AI_OBJECT_IN_USE: " + + IntToString(GetLocalInt(oLocked, AI_OBJECT_IN_USE)) + "]" + + " bForce: " + IntToString(bForce)); + if(GetLocalInt(oLocked, AI_OBJECT_IN_USE)) return FALSE; + string sTag = GetTag(oCreature); + // Attempt to cast knock because its always safe to cast it, even on a trapped object. + if(ai_AttempToCastKnockSpell(oLocked, oCreature)) return TRUE; + // First, let's see if we notice that it's trapped + if(GetTrapDetectedBy(oCreature, oLocked)) + { + // Ick! Try and disarm the trap first + if(ai_ReactToTrap(oCreature, oLocked, bForce)) return TRUE; + } + if(GetLockKeyRequired(oLocked)) + { + // We might be able to open this. + string sKeyTag = GetLockKeyTag(oLocked); + // Do we have the key? + object oKey = ai_GetCreatureHasItem(oCreature, sKeyTag, FALSE); + if(AI_DEBUG) ai_Debug("0i_actions", "1469", "Requires a Key! sKeyTag: " + + sKeyTag + " Has key oKey: " + GetName(oKey)); + if(oKey != OBJECT_INVALID) + { + int nObjectType = GetObjectType(oLocked); + if(nObjectType == OBJECT_TYPE_DOOR) return ai_AttemptToOpenDoor(oCreature, oLocked, bForce); + else if (nObjectType == OBJECT_TYPE_PLACEABLE) + { + SetLocalInt(oLocked, AI_OBJECT_IN_USE, TRUE); + DelayCommand(18.0, DeleteLocalInt(oLocked, AI_OBJECT_IN_USE)); + AssignCommand(oCreature, ActionUnlockObject(oLocked)); + // Let them know we did it! + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 6, ":44:42:31:35:")); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oLocked, AI_OBJECT_IN_USE))); + // Continue checking for traps, locks, and loot. + AssignCommand(oCreature, ActionDoCommand(ai_ActionCheckNearbyObjects(oCreature))); + return TRUE; + } + } + else + { + if(GetLocalInt(oLocked, "AI_LOCKED_" + sTag) && !bForce) return FALSE; + // Let them know we can't get this done!. + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oLocked) + " is special! It requires a special key to open."))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oLocked, "AI_LOCKED_" + sTag, TRUE); + return FALSE; + } + } + if(bForce || ai_GetAIMode(oCreature, AI_MODE_PICK_LOCKS)) + { + // We must have ranks in open locks to actually open the lock! + if(GetSkillRank(SKILL_OPEN_LOCK, oCreature, TRUE)) + { + int nSkill = GetSkillRank(SKILL_OPEN_LOCK, oCreature); + int nLockDC = GetLockUnlockDC(oLocked); + object oPicks = ai_GetBestPicks(oCreature, nLockDC); + int nPickBonus = GetLocalInt(oPicks, "AI_BONUS"); + if(AI_DEBUG) ai_Debug("0i_actions", "1497", "I have picks: " + GetName(oPicks) + + " nSkill :" + IntToString(nSkill) + " nPickBonus: " + + IntToString(nPickBonus) + " + 20 = " + + IntToString(nSkill + nPickBonus + 20) + + " nLockDC: " + IntToString(nLockDC)); + if(nSkill + 20 + nPickBonus >= nLockDC) + { + SetLocalInt(oLocked, AI_OBJECT_IN_USE, TRUE); + DelayCommand(18.0, DeleteLocalInt(oLocked, AI_OBJECT_IN_USE)); + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionWait(1.0)); + AssignCommand(oCreature, ActionUseSkill(SKILL_OPEN_LOCK, oLocked, 0, oPicks)); + AssignCommand(oCreature, ActionWait(1.0)); + // Let them know we did it! + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":44:42:26:31:35:")); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oLocked, AI_OBJECT_IN_USE))); + // Continue checking for traps, locks, and loot. + AssignCommand(oCreature, ActionDoCommand(ai_ActionCheckNearbyObjects(oCreature))); + return TRUE; + } + else if(!GetLocalInt(oLocked, "AI_LOCKED_" + sTag)) + { + // Let them know we can't get this done! + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "I'm not skilled enough to pick the lock on this " + GetName(oLocked) + "!", TRUE))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oLocked, "AI_LOCKED_" + sTag, TRUE); + return FALSE; + } + } + } + if(bForce || ai_GetAIMode(oCreature, AI_MODE_BASH_LOCKS)) + { + //AssignCommand(oCreature, ai_ClearCreatureActions()); + // Check to make sure we are not using a ranged weapon. + if(!ai_GetIsRangeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature))) + { + if(ai_CheckClassType(oCreature, CLASS_TYPE_MONK)) ai_EquipBestMonkMeleeWeapon(oCreature); + else ai_EquipBestMeleeWeapon(oCreature); + AssignCommand(oCreature, ActionWait(1.0)); + if(ai_TryImprovedPowerAttackFeat(oCreature, oLocked)) return TRUE; + if(ai_TryPowerAttackFeat(oCreature, oLocked)) return TRUE; + if(ai_TryFlurryOfBlowsFeat(oCreature, oLocked)) return TRUE; + AssignCommand(oCreature, ActionAttack(oLocked)); + return TRUE; + } + if(GetLocalInt(oLocked, "AI_LOCKED_" + sTag) && !bForce) return FALSE; + // Let them know we can't get this done!. + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "I cannot bash this " + GetName(oLocked) + " open!", TRUE))); + SetLocalInt(oLocked, "AI_LOCKED_" + sTag, TRUE); + return FALSE; + } + if(bForce || ai_GetAIMode(oCreature, AI_MODE_PICKUP_ITEMS)) + { + if(GetLocalInt(oLocked, "AI_LOCKED_" + sTag) && !bForce) return FALSE; + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oLocked) + " is locked!", TRUE))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oLocked, "AI_LOCKED_" + sTag, TRUE); + } + return FALSE; +} +int ai_AttemptToOpenDoor(object oCreature, object oDoor, int bForce = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_actions", "1542", "Attempting to open " + + GetName(oDoor) + " [AI_OBJECT_IN_USE: " + + IntToString(GetLocalInt(oDoor, AI_OBJECT_IN_USE)) + "] " + + " IsOpen: " + IntToString(GetIsOpen(oDoor)) + + " Plot: " + IntToString(GetPlotFlag(oDoor)) + "."); + if(!ai_GetAIMode(oCreature, AI_MODE_OPEN_DOORS) && !bForce) return FALSE; + if(GetLocalInt(oDoor, AI_OBJECT_IN_USE)) return FALSE; + if(GetIsOpen(oDoor)) return FALSE; + string sTag = GetTag(oCreature); + if(GetIsTrapped(oDoor)) + { + if(GetTrapDetectedBy(oDoor, GetMaster(oCreature))) SetTrapDetectedBy(oDoor, oCreature); + if(GetTrapDetectedBy(oDoor, oCreature)) + { + if(GetLocalInt(oDoor, "AI_SAW_TRAP_" + sTag)) return FALSE; + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oDoor) + " is trapped!", TRUE)); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oDoor, "AI_SAW_TRAP_" + sTag, TRUE); + return FALSE; + } + } + if(GetLocked(oDoor)) + { + if(GetLocalInt(oDoor, "AI_LOCKED_" + sTag)) return FALSE; + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oDoor) + " is locked!", TRUE))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oDoor, "AI_LOCKED_" + sTag, TRUE); + return FALSE; + } + SetLocalInt(oDoor, AI_OBJECT_IN_USE, TRUE); + DelayCommand(18.0, DeleteLocalInt(oDoor, AI_OBJECT_IN_USE)); + AssignCommand(oCreature, ActionOpenDoor(oDoor, TRUE)); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oDoor, AI_OBJECT_IN_USE))); + return TRUE; +} +void ai_ActionCheckNearbyObjects(object oCreature) +{ + if(ai_GetIsBusy(oCreature)) return; + ai_CheckNearbyObjects(oCreature); +} +int ai_CheckNearbyObjects(object oCreature) +{ + object oMaster = ai_GetPlayerMaster(oCreature); + location lMaster = GetLocation(oMaster); + int nObjectType, bIgnore; + int nFilter = OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_TRIGGER | OBJECT_TYPE_ITEM; + float fLockRange, fDoorRange, fLootRange, fObjectDistance; + float fTrapRange = GetLocalFloat(oCreature, AI_TRAP_CHECK_RANGE); + if(ai_GetAIMode(oCreature, AI_MODE_PICK_LOCKS) || + ai_GetAIMode(oCreature, AI_MODE_BASH_LOCKS)) fLockRange = GetLocalFloat(oCreature, AI_LOCK_CHECK_RANGE); + if(ai_GetAIMode(oCreature, AI_MODE_PICKUP_ITEMS)) fLootRange = GetLocalFloat(oCreature, AI_LOOT_CHECK_RANGE); + if(ai_GetAIMode(oCreature, AI_MODE_OPEN_DOORS)) fDoorRange = GetLocalFloat(oCreature, AI_OPEN_DOORS_RANGE); + if(AI_DEBUG && fTrapRange != 0.0) ai_Debug("0i_actions", "1579", " Checking " + FloatToString(fTrapRange, 0, 0) + " foot area for traps."); + if(AI_DEBUG && fLootRange != 0.0) ai_Debug("0i_actions", "1580", " Checking " + FloatToString(fLootRange, 0, 0) + " foot area for traps."); + if(AI_DEBUG && fLockRange != 0.0) ai_Debug("0i_actions", "1581", " Checking " + FloatToString(fLockRange, 0, 0) + " foot area for locks."); + if(AI_DEBUG && fDoorRange != 0.0) ai_Debug("0i_actions", "1582", " Checking " + FloatToString(fDoorRange, 0, 0) + " foot area for doors."); + float fLongestRange = fTrapRange; + vector vCreature = GetPositionFromLocation(GetLocation(oCreature)); + if(fLongestRange < fLootRange) fLongestRange = fLootRange; + if(fLongestRange < fLockRange) fLongestRange = fLockRange; + if(fLongestRange < fDoorRange) fLongestRange = fDoorRange; + object oObject = GetFirstObjectInShape(SHAPE_SPHERE, fLongestRange, lMaster, TRUE, nFilter); + while(oObject != OBJECT_INVALID) + { + fObjectDistance = GetDistanceBetween(oMaster, oObject); + if(AI_DEBUG) ai_Debug("0i_actions", "1651", "Checking Nearby Objects: " + + GetName(oObject) + " fDistance: " + FloatToString(fObjectDistance, 0, 2)); + if(GetTrapDetectedBy(oObject, oCreature)) + { + if(fTrapRange >= fObjectDistance) + { + if(ai_ReactToTrap(oCreature, oObject)) return TRUE; + } + } + if(GetLocked(oObject)) + { + if(fLockRange >= fObjectDistance) + { + if(ai_AttemptToByPassLock(oCreature, oObject)) return TRUE; + } + } + nObjectType = GetObjectType(oObject); + if(fDoorRange >= fObjectDistance && nObjectType == OBJECT_TYPE_DOOR) + { + if(ai_AttemptToOpenDoor(oCreature, oObject)) return TRUE; + } + if(fLootRange >= fObjectDistance) + { + if(nObjectType == OBJECT_TYPE_PLACEABLE) + { + if(!GetLocalInt(oObject, AI_OBJECT_IN_USE) && + ai_IsContainerLootable(oCreature, oObject)) + { + if(GetLocked(oObject)) + { + string sTag = GetTag(oCreature); + if(GetLocalInt(oObject, "AI_LOCKED_" + sTag)) return FALSE; + AssignCommand(oCreature, ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oObject) + " is locked!", TRUE))); + ActionDoCommand(ai_HaveCreatureSpeak(oCreature, 8, ":47:30:43:5:36:")); + SetLocalInt(oObject, "AI_LOCKED_" + sTag, TRUE); + return FALSE; + } + ai_ClearCreatureActions(); + ActionMoveToObject(oObject, TRUE); + AssignCommand(oCreature, ActionDoCommand(ai_SearchObject(oCreature, oObject, oMaster))); + return TRUE; + } + } + else if(nObjectType == OBJECT_TYPE_ITEM) + { + if(ai_ShouldIPickItUp(oCreature, oObject)) + { + ActionPickUpItem(oObject); + return TRUE; + } + } + } + oObject = GetNextObjectInShape(SHAPE_SPHERE, fLongestRange, lMaster, TRUE, nFilter); + } + return FALSE; +} +void ai_DetermineSpecialBehavior(object oCreature) +{ + object oTarget = ai_GetNearestEnemy(oCreature, 1, 7, 7, -1, -1, TRUE); + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE)) + { + if(ai_GetIsInCombat(oCreature)) ai_DoMonsterCombatRound(oTarget); + // * if not attacking, then wander. + else + { + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionRandomWalk()); + return; + } + } + else if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE)) + { + if(GetIsObjectValid(ai_GetAttackedTarget(oCreature, TRUE, TRUE))) + { + if(oTarget != OBJECT_INVALID && GetDistanceBetween(oCreature, oTarget) <= 6.0) + { + if(!GetIsFriend(oTarget)) + { + if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_coward"); + ActionMoveAwayFromObject(oTarget, TRUE, AI_RANGE_LONG); + } + } + } + } + else if(!IsInConversation(OBJECT_SELF)) + { + AssignCommand(oCreature, ai_ClearCreatureActions()); + AssignCommand(oCreature, ActionRandomWalk()); + return; + } + } +} +//This function is used only because ActionDoCommand can only accept void functions +void ai_CreateSignPostNPC(string sTag, location lLocal) +{ + CreateObject(OBJECT_TYPE_CREATURE, sTag, lLocal); +} +void ai_ActivateFleeToExit(object oCreature) +{ + //minor optimizations - only grab these variables when actually needed + //can make for larger code, but it's faster + //object oExitWay = GetWaypointByTag("EXIT_" + GetTag(OBJECT_SELF)); + //location lLocal = GetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT"); + //string sTag = GetTag(OBJECT_SELF); + int nPlot = GetLocalInt(oCreature, "NW_GENERIC_MASTER"); + if(nPlot & NW_FLAG_TELEPORT_RETURN || nPlot & NW_FLAG_TELEPORT_LEAVE) + { + effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCreature); + if(nPlot & NW_FLAG_TELEPORT_RETURN) + { + location lLocal = GetLocalLocation(oCreature, "NW_GENERIC_START_POINT"); + string sTag = GetTag(oCreature); + DelayCommand(6.0, AssignCommand(oCreature, ActionDoCommand(ai_CreateSignPostNPC(sTag, lLocal)))); + } + AssignCommand(oCreature, ActionDoCommand(DestroyObject(oCreature, 0.75))); + } + else + { + if(nPlot & NW_FLAG_ESCAPE_LEAVE) + { + object oExitWay = GetWaypointByTag("EXIT_" + GetTag(oCreature)); + ActionMoveToObject(oExitWay, TRUE); + AssignCommand(oCreature, ActionDoCommand(DestroyObject(oCreature, 1.0))); + } + else if(nPlot & NW_FLAG_ESCAPE_RETURN) + { + string sTag = GetTag(oCreature); + object oExitWay = GetWaypointByTag("EXIT_" + sTag); + ActionMoveToObject(oExitWay, TRUE); + location lLocal = GetLocalLocation(oCreature, "NW_GENERIC_START_POINT"); + DelayCommand(6.0, AssignCommand(oCreature, ActionDoCommand(ai_CreateSignPostNPC(sTag, lLocal)))); + AssignCommand(oCreature, ActionDoCommand(DestroyObject(oCreature, 1.0))); + } + } +} +int ai_GetFleeToExit(object oCreature) +{ + int nPlot = GetLocalInt(oCreature, "NW_GENERIC_MASTER"); + if(nPlot & NW_FLAG_ESCAPE_RETURN) return TRUE; + else if(nPlot & NW_FLAG_ESCAPE_LEAVE) return TRUE; + else if(nPlot & NW_FLAG_TELEPORT_RETURN) return TRUE; + else if(nPlot & NW_FLAG_TELEPORT_LEAVE) return TRUE; + return FALSE; +} +void ai_ActionInitialization() +{ + SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE); + SetAnimationCondition(NW_ANIM_FLAG_INITIALIZED); + SetLocalLocation(OBJECT_SELF, "ANIM_START_LOCATION", GetLocation(OBJECT_SELF)); +} +// Start interacting with a placeable object +void ai_ActionStartInteracting(object oPlaceable) +{ + SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING); + ActionMoveToObject(oPlaceable, FALSE, DISTANCE_TINY); + ActionDoCommand(SetFacingPoint(GetPosition(oPlaceable))); + SetCurrentInteractionTarget(oPlaceable); + AnimActionPlayRandomInteractAnimation(oPlaceable); +} + +void ai_ActionStopInteracting() +{ + AnimActionRandomMoveAway(GetCurrentInteractionTarget(), DISTANCE_LARGE); + SetCurrentInteractionTarget(OBJECT_INVALID); + SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING, FALSE); + AnimActionTurnAround(); + AnimActionPlayRandomAnimation(); +} + +// Start talking with a friend +void ai_ActionStartTalking(object oFriend, int nHDiff=0) +{ + object oMe = OBJECT_SELF; + ActionMoveToObject(oFriend, FALSE, DISTANCE_TINY); + AnimActionPlayRandomGreeting(nHDiff); + AssignCommand(oFriend, ActionMoveToObject(oMe, FALSE, DISTANCE_TINY)); + AssignCommand(oFriend, AnimActionPlayRandomGreeting(0 - nHDiff)); + SetCurrentFriend(oFriend); + AssignCommand(oFriend, SetCurrentFriend(oMe)); + ActionDoCommand(SetFacingPoint(GetPosition(oFriend))); + AssignCommand(oFriend, ActionDoCommand(SetFacingPoint(GetPosition(oMe)))); + SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING); + SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, TRUE, oFriend); +} +void ai_ActionStopTalking(object oFriend, int nHDiff=0) +{ + object oMe = OBJECT_SELF; + AnimActionPlayRandomGoodbye(nHDiff); + AnimActionRandomMoveAway(oFriend, DISTANCE_LARGE); + AssignCommand(oFriend, AnimActionPlayRandomGoodbye(0 - nHDiff)); + AssignCommand(oFriend, AnimActionRandomMoveAway(oMe, DISTANCE_HUGE)); + SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, FALSE); + SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, FALSE, oFriend); +} +object ai_GetRandomFriend(float fMaxDistance) +{ + object oCreature = OBJECT_SELF; + location lStartLocation = GetLocalLocation(oCreature, "ANIM_START_LOCATION"); + object oFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION, + REPUTATION_TYPE_FRIEND, + oCreature, d2(), + CREATURE_TYPE_PERCEPTION, + PERCEPTION_SEEN); + //SendMessageToPC(GetFirstPC(), " 0i_actions, 1748 oFriend: " + GetName(oFriend) + + // " AnimationCondition: " + IntToString(GetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE, oFriend)) + + // " Conversation: " + IntToString(IsInConversation(oFriend)) + + // " Combat: " + IntToString(GetIsInCombat(oFriend)) + + // " Distance: " + FloatToString(GetDistanceBetweenLocations(GetLocation(oFriend), lStartLocation), 0,0 )); + if(fMaxDistance > 20.0) fMaxDistance = 20.0; + if(GetIsObjectValid(oFriend) + && !GetIsPC(oFriend) + && !GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, oFriend) + && !IsInConversation(oFriend) + && !GetIsInCombat(oFriend) + && GetDistanceBetweenLocations(GetLocation(oFriend), lStartLocation) <= fMaxDistance) + { + return oFriend; + } + + return OBJECT_INVALID; +} +int ai_ActionFindFriend(float fMaxDistance) +{ + // Try and find a friend to talk to. + object oFriend = ai_GetRandomFriend(fMaxDistance); + //SendMessageToPC(GetFirstPC(), GetName(oFriend) + " TALKING: " + IntToString(GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, oFriend))); + if(GetIsObjectValid(oFriend) && !GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, oFriend)) + { + int nHDiff = GetHitDice(OBJECT_SELF) - GetHitDice(oFriend); + ai_ActionStartTalking(oFriend, nHDiff); + return TRUE; + } + return FALSE; +} +object ai_GetRandomObjectbyTag(string sTag, float fMaxDistance) +{ + int nIndex; + if(fMaxDistance < DISTANCE_MEDIUM) nIndex = d4(); + else if (fMaxDistance < DISTANCE_HUGE) nIndex = d8(); + else nIndex = d10(); + location lStartLocation = GetLocalLocation(OBJECT_SELF, "ANIM_START_LOCATION"); + if(fMaxDistance > 20.0) fMaxDistance = 20.0; + object oObject = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE, lStartLocation, nIndex); + while(nIndex > 0) + { + if(GetTag(oObject) == sTag && + GetDistanceBetweenLocations(GetLocation(oObject), lStartLocation) <= fMaxDistance) break; + oObject = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE, lStartLocation, --nIndex); + } + if(GetIsObjectValid(oObject)) + return oObject; + return OBJECT_INVALID; +} +int ai_ActionSitInChair(float fMaxDistance) +{ + object oChair = GetRandomObjectByTag("Chair", fMaxDistance); + if (GetIsObjectValid(oChair) && + !GetIsObjectValid(GetSittingCreature(oChair))) + { + ActionSit(oChair); + SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING); + return TRUE; + } + return FALSE; +} +object ai_GetRandomUseableObject(float fMaxDistance) +{ + int nIndex; + if(fMaxDistance < DISTANCE_MEDIUM) nIndex = d2(); + else if (fMaxDistance < DISTANCE_HUGE) nIndex = d4(); + else nIndex = d6(); + location lStartLocation = GetLocalLocation(OBJECT_SELF, "ANIM_START_LOCATION"); + if(fMaxDistance > 20.0) fMaxDistance = 20.0; + object oObject = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE, lStartLocation, nIndex); + while(nIndex > 0) + { + if(GetUseableFlag(oObject) && !GetLocked(oObject) && + GetDistanceBetweenLocations(GetLocation(oObject), lStartLocation) <= fMaxDistance) break; + oObject = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE, lStartLocation, --nIndex); + } + if(GetIsObjectValid(oObject)) + return oObject; + return OBJECT_INVALID; +} +int ai_ActionFindPlaceable(float fMaxDistance) +{ + object oPlaceable = ai_GetRandomUseableObject(fMaxDistance); + if(GetIsObjectValid(oPlaceable)) + { + ai_ActionStartInteracting(oPlaceable); + return 1; + } + return 0; +} +int ai_ActionCheckDoor(float fMaxDistance) +{ + int nIndex = 1; + object oCreature = OBJECT_SELF; + location lStartLocation = GetLocalLocation(oCreature, "ANIM_START_LOCATION"); + if(fMaxDistance > 20.0) fMaxDistance = 20.0; + object oDoor = GetNearestObject(OBJECT_TYPE_DOOR, oCreature); + while(oDoor != OBJECT_INVALID) + { + if(GetDistanceBetweenLocations(GetLocation(oDoor), lStartLocation) <= fMaxDistance) + { + // Make sure everyone doesn't run to close or open the same door. + if(!GetLocalInt(oDoor, "DOOR_INTERACTION")) + { + if(GetIsOpen(oDoor)) + { + //SendMessageToPC(GetFirstPC(), GetName(oCreature) + + // " Closing " + GetName(oDoor) + "."); + SetLocalInt(oDoor, "DOOR_INTERACTION", TRUE); + ActionCloseDoor(oDoor); + AssignCommand(oDoor, ActionDoCommand(SetLocalInt(oDoor, "DOOR_INTERACTION", FALSE))); + return TRUE; + } + else if(GetLocalInt(GetModule(), AI_RULE_OPEN_DOORS)) + { + //SendMessageToPC(GetFirstPC(), GetName(oDoor) + " Locked: " + + // IntToString(GetLocked(oDoor)) + " Trapped: " + + // IntToString(GetIsTrapped(oDoor)) + + // " Plot: " + IntToString(GetPlotFlag(oDoor))); + if(!GetLocked(oDoor) && + !GetIsTrapped(oDoor) && + !GetPlotFlag(oDoor)) + { + //SendMessageToPC(GetFirstPC(), GetName(oCreature) + + // " Opening " + GetName(oDoor) + "."); + SetLocalInt(oDoor, "DOOR_INTERACTION", TRUE); + ActionOpenDoor(oDoor); + // If a door has been opened lets not go right behind and close for a minute. + DelayCommand(60.0, SetLocalInt(oDoor, "DOOR_INTERACTION", FALSE)); + return TRUE; + } + } + } + } + oDoor = GetNearestObject(OBJECT_TYPE_DOOR, oCreature, ++nIndex); + } + return FALSE; +} +int ai_ActionInteraction() +{ + // If we're talking, either keep going or stop. + // Low prob of stopping, since both parties have + // a chance and conversations are cool. + if(GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING)) + { + object oFriend = GetCurrentFriend(); + //SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF) + " Is talking to " + GetName(oFriend)); + int nHDiff = GetHitDice(OBJECT_SELF) - GetHitDice(oFriend); + if(Random(100) < 20) + { + //SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF) + " I'm done talking!"); + ai_ActionStopTalking(oFriend, nHDiff); + return TRUE; + } + AnimActionPlayRandomTalkAnimation(nHDiff); + return TRUE; + } + // If we're interacting with a placeable, either keep going or stop. + // High probability of stopping, since looks silly to + // constantly turn something on-and-off. + if(GetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING)) + { + //SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF) + " Is interacting."); + if(Random(100) < 40) + { + //SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF) + " I'm done interacting!"); + ai_ActionStopInteracting(); + return TRUE; + } + AnimActionPlayRandomInteractAnimation(GetCurrentInteractionTarget()); + return TRUE; + } + return FALSE; +} +location ai_GetWalkingLocation(object oSource, float fDistance) +{ + location lStart = GetLocation(oSource); + // Try to move in a north/south/east/west direction that will allow better + // movement around the map! + float fFacing = GetFacing(oSource); + if(Random(100) < 25) fFacing = IntToFloat(Random(360)); + float fAngle; + if(fFacing > 315.0 || fFacing < 45.0) fAngle = DIRECTION_EAST; + else if(fFacing < 135.0) fAngle = DIRECTION_NORTH; + else if(fFacing < 225.0) fAngle = DIRECTION_WEST; + else fAngle = DIRECTION_SOUTH; + fAngle += IntToFloat(Random(20) - 10); + float fOrientation = fAngle; + return GenerateNewLocationFromLocation(lStart, fDistance, fAngle, fOrientation); +} +void ai_ActionRandomWalk(float fMaxDistance) +{ + // If we stay within our alloted distance then we can walk to the new location. + location lStartLocation = GetLocalLocation(OBJECT_SELF, "ANIM_START_LOCATION"); + int nRandom = FloatToInt(fMaxDistance); + if(nRandom > 20) nRandom = 20; + float fRandom = IntToFloat(Random(nRandom) + 1); + location lNewLocation = ai_GetWalkingLocation(OBJECT_SELF, fRandom); + if(AI_DEBUG) ai_Debug("0i_actions", "2092", GetName(OBJECT_SELF) + " is walking " + + FloatToString(GetDistanceBetweenLocations(lNewLocation, lStartLocation), 0, 0) + + " distance of fMaxDistance: " + FloatToString(fMaxDistance, 0, 0)); + ActionMoveToLocation(lNewLocation); +} +void ai_Actions() +{ + float fMaxDistance = GetLocalFloat(GetModule(), AI_RULE_WANDER_DISTANCE); + // Are we interacting? If so continue else see what else there is to do. + if(ai_ActionInteraction()) return; + // If we got here, we're not busy + ClearAllActions(); + // Check for chance to do an action to keep things interesting. + int nRoll = Random(100); + if(fMaxDistance < 2.0) + { + if(nRoll < 51) AnimActionPlayRandomAnimation(); + return; + } + int nRace = GetRacialType(OBJECT_SELF); + if(nRace != RACIAL_TYPE_ABERRATION && nRace != RACIAL_TYPE_ANIMAL && + nRace != RACIAL_TYPE_BEAST && nRace != RACIAL_TYPE_MAGICAL_BEAST && + nRace != RACIAL_TYPE_OOZE && nRace != RACIAL_TYPE_VERMIN) + { + if(nRoll < 5) if(ai_ActionSitInChair(fMaxDistance)) return; + // Open or close a door + if(nRoll < 20) if(ai_ActionCheckDoor(fMaxDistance)) return; + // Fiddle with a placeable + if(nRoll < 40) if(ai_ActionFindPlaceable(fMaxDistance)) return; + // Start talking to a friend + if(nRoll < 50) if(ai_ActionFindFriend(fMaxDistance)) return; + } + // Lets walk around. + if(nRoll < 80) + { + ai_ActionRandomWalk(fMaxDistance); + return; + } + // If we find nothing interesting to do then just stay put and look interesting. + AnimActionPlayRandomAnimation(); +} +int ai_CheckCurrentAction() +{ + int nAction = GetCurrentAction(); + if(nAction == ACTION_SIT) + { + // low prob of getting up, so we don't bop up and down constantly + if (Random(10) == 0) + { + AnimActionGetUpFromChair(); + return TRUE; + } + } + else if(nAction != ACTION_INVALID) + { + // Sometimes we cannot do an action so lets break out sometimes. + if((nAction == ACTION_CLOSEDOOR || + nAction == ACTION_OPENDOOR || + nAction == ACTION_MOVETOPOINT) && Random(100) < 20) return FALSE; + // we're doing *something*, don't switch + //AnimDebug("performing action"); + return TRUE; + } + return FALSE; +} +void ai_AmbientAnimations() +{ + if(!GetAnimationCondition(NW_ANIM_FLAG_INITIALIZED)) ai_ActionInitialization(); + // Check if we should turn off + if(!CheckIsAnimActive(OBJECT_SELF)) return; + // Check current actions so we don't interrupt something in progress + if(ai_CheckCurrentAction()) return; + // First check: go back to starting position and rest if we are hurt + //if(AnimActionRest()) return; + // If we get here then lets go see what we can do! + ai_Actions(); +} diff --git a/src/module/nss/0i_associates.nss b/src/module/nss/0i_associates.nss new file mode 100644 index 0000000..2309160 --- /dev/null +++ b/src/module/nss/0i_associates.nss @@ -0,0 +1,2192 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0i_associates + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Scripts used for Associates. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +#include "nw_inc_gff" +// Return TRUE if oCreature can attack based on current modes and actions. +int ai_CanIAttack(object oCreature); +// Returns the nearest locked object from oMaster. +object ai_GetNearestLockedObject(object oCreature); +// Will look for the oTarget or go to the oSpeaker depending on the situation. +void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMonster); +// Selects the correct response base on nCommand from oCommander. +// These are given from either a radial menu option or voice command. +void ai_SelectAssociateCommand(object oCreature, object oCommander, int nCommand); +// Set nAction for the caller to pass to their associates. i.e. For henchmans summons. +void ai_PassActionToAssociates(object oCreature, int nAction, int bStatus = TRUE); +// Set Set the AI Mode to oAssociate and their associates. +void ai_PassAIModeToAssociates(object oAssociate, int nAIMode, int bStatus = TRUE); +// Set oCreature's ai scripts based on its first class or the variable "AI_DEFAULT_SCRIPT". +// bSetBasicAIScript set to TRUE will skip defensive and ambush tactic type scripts. +void ai_SetAssociateAIScript(object oCreature, int bCheckTacticScripts = TRUE); +// Returns TRUE if oCreature can speak. +int ai_CanISpeak(object oCreature); +// Cleansup any henchman actions and then removes them from the PC's faction. +void ai_FireHenchman(object oPC, object oHenchman); +// Will cast defensive spells (Buffs) on oPC's party from oCreature. +void ai_HenchmanCastDefensiveSpells(object oCreature, object oPC); +// Returns TRUE if we are starting combat due to an enemy being near. +// This should be checked after any "is in combat" checks. +int ai_CheckForCombat(object oCreature, int bMonster); +// Checks all perceived creatures to see if we should calculate a combat round +// or start combat for Associates. +void ai_AssociateEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception); +// Checks all perceived creatures to see if we should calculate a combat round +// or start combat for Monsters. +void ai_MonsterEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception); +// Copies all int, float, and string variables from oOldObject to oNewObject. +void ai_CopyObjectVariables(object oOldObject, object oNewObject); +//****************************************************************************** +//********************* Creature event scripts ********************************* +//****************************************************************************** + +// Add to nw_ch_aca OnRested event script of henchman. +void ai_OnRested(object oCreature); + +//****************************************************************************** +//******************* Associate AI option scripts ****************************** +//****************************************************************************** + +// Increments/Decrements the following distance of associates. +void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType); +// Turns on/off Ranged combat for oAssociate. +void ai_Ranged(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Ignore enemy associates for oAssociate. +void ai_Ignore_Associates(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Ignore floor traps for oAssociate. +void ai_Ignore_Traps(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Search for oAssociate. +void ai_Search(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Stealth for oAssociate. +void ai_Stealth(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Open Doors for oAssociate. +void ai_OpenDoor(object oPC, object oAssociate, string sAssociateType); +// Turns on/off Picking/Bashing locks for oAssociate. +void ai_Locks(object oPC, object oAssociate, string sAssociateType, int nMode); +// Turns on/off Disarming of Traps for oAssociate. +void ai_Traps(object oPC, object oAssociate, string sAssociateType); +// Turns on/off the amount of speaking for oAssociate. +void ai_ReduceSpeech(object oPC, object oAssociate, string sAssociateType); +// Turns on/off use of offensive/defensive spells. +void ai_UseOffensiveMagic(object oPC, object oAssociate, int bDefensive, int bOffensive, string sAssociateType); +// Turns on/off magic use. +void ai_UseMagic(object oPC, object oAssociate, string sAssociateType); +// Turn Magic Item use on/off for oAssociates. +void ai_UseMagicItems(object oPC, object oAssociate, string sAssociateType); +// Adjusts loot options for oAssociate +void ai_Loot(object oPC, object oAssociate, string sAssociateType); +// Adjust loot options for oAssociate +void ai_Spontaneous(object oPC, object oAssociate, string sAssociateType); +// Increments/Decrements the magic use variable for the AI. +void ai_MagicIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType); +// Increments/Decrements the Loot Range use variable for the AI. +void ai_LootRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType); +// Increments/Decrements the Lock Range use variable for the AI. +void ai_LockRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType); +// Increments/Decrements the Trap Range use variable for the AI. +void ai_TrapRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType); +// Increments/Decrements the Open Door Range use variable for the AI. +void ai_OpenDoorIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType); +// Saves a new AI script for oAssociate. +void ai_SaveAIScript(object oPC, object oAssociate, int nToken); +// Button action for buffing a PC. +void ai_Buff_Button(object oPC, object oAssociate, int nOption, string sAssociateType); +// Button action for setting healing ranges. +void ai_Heal_Button(object oPC, object oAssociate, int nIncrement, string sVar, string sAssociateType); +// Button action for turning healing on/off. +void ai_Heal_OnOff(object oPC, object oAssociate, string sAssociateType, int nMode); +// Button action for selecting a target to follow. +void ai_FollowTarget(object oPC, object oAssociate); +// Code to make oCreature guard oMaster. +void ai_Philos_Guard(object oMaster, object oCreature); +// Code to make OBJECT_SELF follow oMaster. +void ai_Philos_Follow(object oMaster); +// Code to make OBJECT_SELF hold at their location. +void ai_Philos_StandGround(object oMaster); +// Code to make oCreature attack the nearest enemy. +void ai_Philos_AttackNearest(object oMaster, object oCreature); +// Code to make oCreature turn search mode on. +void ai_Philos_SetSearch(object oMaster, object oCreature, string sAssociateType, int bTurnOn); +// Code to make oCreature turn stealth mode on. +void ai_Philos_SetStealth(object oMaster, object oCreature, string sAssociateType, int bTurnOn); +// Button action for giving commands to associates. +void ai_DoCommand(object oPC, object oAssociate, int nCommand); +// Button action to have associate do an action based on the target via OnPlayer Target event. +void ai_Action(object oPC, object oAssociate); +// Toggles between normal ai script and special tactic ai scripts. +void ai_AIScript(object oPC, object oAssociate, string sAssociate, int nToken); +// Has the PC select a Trap and then place it on the ground from an associate. +void ai_HavePCPlaceTrap(object oPC, object oAssociate); +// Jumps oAssociate to oPC, if oPC == oAssociate it jumps all oAssocites to oPC. +void ai_JumpToPC(object oPC, object oAssociate); +// Allow oAssociate to use no clipping. +void ai_GhostMode(object oPC, object oAssociate, int nToken, string sAssociateType); +// Changes the camera view from either the player to the associate or back. +void ai_ChangeCameraView(object oPC, object oAssociate); +// Checks that the oAssociate is within sight and then opens the inventory. +void ai_OpenInventory(object oAssociate, object oPC); +// Executes an installed plugin. +void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0); + +int ai_CanIAttack(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_associate", "122", "Can I attack? Hold mode: " + + IntToString(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) + + " Follow mode: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) + + " Action (19/4): " + IntToString(GetCurrentAction(oCreature))); + if(ai_GetIsCharacter(oCreature)) return TRUE; + int nAction = GetCurrentAction(oCreature); + return (!ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND) && + !ai_GetAIMode(oCreature, AI_MODE_FOLLOW) && + nAction != ACTION_ITEMCASTSPELL && + nAction != ACTION_CASTSPELL); +} +object ai_GetNearestLockedObject(object oCreature) +{ + int nCnt = 1; + object oMaster = GetMaster(oCreature); + float fRange = GetLocalFloat(oCreature, AI_TRAP_CHECK_RANGE); + location lCreature = GetLocation(oCreature); + object oObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, lCreature, nCnt); + while (oObject != OBJECT_INVALID || GetDistanceBetween(oMaster, oObject) > fRange) + { + if(GetLocked(oObject) && ai_GetIsInLineOfSight(oMaster, oObject)) return oObject; + oObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, lCreature, ++nCnt); + } + return OBJECT_INVALID; +} +void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMonster) +{ + if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return; + if(oSpeaker == oTarget && d100() < 34) + { + // Let them know we heard something in the distance!. + if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) + { + string sSpeak = "I heard something!"; + int nRoll = d8(); + if(nRoll == 1) sSpeak = "Did you hear that?"; + if(nRoll == 2) sSpeak = "What was that noise?"; + if(nRoll == 3) sSpeak = "Something is moving."; + if(nRoll == 4) sSpeak = "Lookout! I heard a noise."; + if(nRoll == 5) sSpeak = "Listen! We have company."; + AssignCommand(oCreature, ai_HaveCreatureSpeak(oCreature, 0, sSpeak)); + } + ai_HaveCreatureSpeak(oCreature, 8, ":43:6:9:10:23:42:"); + } + if(GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_a_peaceful" || + GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_coward") return; + float fDistance, fPerceptionDistance; + if(bMonster) + { + // Check distance from the creature hearing this and the target. + fDistance = GetDistanceBetween(oCreature, oTarget); + fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE); + } + else + { + // We want to use the distance between the PC and target not us. + fDistance = GetDistanceBetween(GetMaster(), oTarget); + fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + } + if(AI_DEBUG) ai_Debug("0i_associates", "175", " fDistance: " + FloatToString(fDistance, 0, 2) + + " fPerceptionDistance: " + FloatToString(fPerceptionDistance, 0, 2) + + " Hiding? " + IntToString(GetStealthMode(oTarget))); + if(fDistance <= fPerceptionDistance) + { + SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE); + if(LineOfSightObject(oCreature, oTarget)) + { + if(fDistance > AI_RANGE_CLOSE) + { + int bMoveForward = TRUE; + // We check this because if the enemy is moving or has not + // started acting then we don't want to move up on them as they + // might move towards us! Just attack! Only sneak attack if they are busy. + int nAction = GetCurrentAction(oTarget); + if(AI_DEBUG) ai_Debug("0i_associates", "189", GetName(oTarget) + " current action: " + IntToString(nAction)); + if(nAction == ACTION_MOVETOPOINT || + nAction == ACTION_INVALID || + nAction == ACTION_RANDOMWALK) bMoveForward = FALSE; + // If they are attacking make sure it is in melee? + // If not then don't move since they might be moving toward us. + if(nAction == ACTION_ATTACKOBJECT) + { + if(!ai_GetNumOfEnemiesInRange(oTarget)) bMoveForward = FALSE; + } + if(bMoveForward) + { + if(AI_DEBUG) ai_Debug("0i_associates", "201", "Running towards combat to engage " + GetName(oTarget)); + ActionMoveToObject(oTarget, TRUE, AI_RANGE_CLOSE); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING))); + return; + } + if(AI_DEBUG) ai_Debug("0i_associates", "207", "Searching for " + GetName(oTarget) + " while moving towards " + GetName(oSpeaker)); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + ActionMoveToObject(oSpeaker); + return; + } + if(AI_DEBUG) ai_Debug("0i_associates", "176", "Moving and searching for " + GetName(oTarget)); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + ActionMoveToLocation(GetLocation(oTarget), FALSE); + //ActionMoveToObject(oTarget, FALSE, AI_RANGE_MELEE); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING))); + return; + } + if(AI_DEBUG) ai_Debug("0i_associates", "218", "No line of sight for " + GetName(oTarget) + ". Moving towards " + GetName(oSpeaker)); + ActionMoveToObject(oSpeaker, TRUE); + AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING))); + } + +} +void ai_ReactToAssociate(object oCreature, object oCommander, int bMonster) +{ + object oTarget = GetLocalObject(oCommander, AI_MY_TARGET); + if (oTarget == OBJECT_INVALID) return; + if(ai_GetIsInCombat(oCreature)) + { + if(oCommander == GetMaster(oCreature) && ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) + { + ai_DoAssociateCombatRound(oCreature, oTarget); + } + else ai_DoAssociateCombatRound(oCreature); + return; + } + ai_FindTheEnemy(oCreature, oCommander, oTarget, bMonster); +} +void ai_SelectAssociateCommand(object oCreature, object oCommander, int nCommand) +{ + object oMaster = GetMaster(oCreature); + // These nCommands can be issued even when the caller is busy. + switch(nCommand) + { + // Master is being attacked by the enemy. + case ASSOCIATE_COMMAND_MASTERGOINGTOBEATTACKED: + { + object oAttacker = GetGoingToBeAttackedBy(oMaster); + if(AI_DEBUG) ai_Debug("0i_associate", "120", GetName(oMaster) + " has been attack by " + + GetName(GetGoingToBeAttackedBy(oMaster)) + "!"); + // Used to set who monsters are attacking. + int nAction = GetCurrentAction(oAttacker); + if(nAction == ACTION_ATTACKOBJECT) SetLocalObject(oAttacker, AI_ATTACKED_PHYSICAL, oMaster); + else if(nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL) + { + SetLocalObject(oAttacker, AI_ATTACKED_SPELL, oMaster); + } + if(!ai_GetIsBusy(oCreature) && ai_CanIAttack(oCreature)) + { + if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound(oCreature); + else ai_FindTheEnemy(oCreature, oCommander, oAttacker, FALSE); + } + return; + } + // Menu used by a player to have the henchman follow them. + case ASSOCIATE_COMMAND_FOLLOWMASTER: + { + if(AI_DEBUG) ai_Debug("0i_associate", "135", GetName(oMaster) + " has commanded " + + GetName(oCreature) + " to FOLLOW."); + AssignCommand(oCreature, ai_Philos_Follow(oMaster)); + return; + } + // Menu used by a player to have the henchman go into NORMAL MODE. + // We also attack the nearest, this keeps henchman going into combat quickly. + case ASSOCIATE_COMMAND_ATTACKNEAREST: + { + if(AI_DEBUG) ai_Debug("0i_associates", "158", GetName(oMaster) + " has commanded " + + GetName(oCreature) + " to attack nearest(NORMAL MODE)."); + ai_Philos_AttackNearest(oMaster, oCreature); + return; + } + // Menu used by a player to have the henchman stay where they are standing. + case ASSOCIATE_COMMAND_STANDGROUND: + { + if(AI_DEBUG) ai_Debug("0i_associate", "189", GetName(oMaster) + " has commanded " + + GetName(OBJECT_SELF) + " to STANDGROUND."); + AssignCommand(oCreature, ai_Philos_StandGround(oMaster)); + return; + } + // Menu used by a player to have the henchman attack anyone who attacks them. + case ASSOCIATE_COMMAND_GUARDMASTER: + { + if(AI_DEBUG) ai_Debug("0i_associate", "211", GetName(oMaster) + " has commanded " + + GetName(oCreature) + " to GAURDMASTER."); + ai_Philos_Guard(oMaster, oCreature); + return; + } + // Menu used by a player to have the henchman heal them as soon as possible. + case ASSOCIATE_COMMAND_HEALMASTER: + { + // Player will be stuck with this variable if they are not using the AI. + DeleteLocalInt(oCommander, "AI_I_AM_BEING_HEALED"); + if(ai_GetIsInCombat(oCreature)) ai_TryHealingTalent(oCreature, ai_GetNumOfEnemiesInRange(oCreature), oCommander); + else AssignCommand(oCreature, ai_ActionTryHealing(oCreature, oCommander)); + return; + } + // Menu used by a player to toggle a henchmans casting options. + case ASSOCIATE_COMMAND_TOGGLECASTING: + { + if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) + { + ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, TRUE); + ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE); + ai_SendMessages(GetName(oCreature) + " will now cast defensive spells only.", AI_COLOR_GRAY, oCommander); + } + else if(ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, TRUE); + ai_SendMessages(GetName(oCreature) + " will now cast offensive spells only.", AI_COLOR_GRAY, oCommander); + } + else if(ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE); + ai_SendMessages(GetName(oCreature) + " will now cast any spell.", AI_COLOR_GRAY, oCommander); + } + else + { + ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, TRUE); + ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE); + ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE); + ai_SendMessages(GetName(oCreature) + " will not use any magic.", AI_COLOR_GRAY, oCommander); + } + aiSaveAssociateModesToDb(oMaster, oCreature); + return; + } + } + // If we are busy then these nCommands are ignored. + if(!ai_GetIsBusy(oCreature)) + { + // Respond to shouts from friendly non-PCs only. + if (ai_CanIAttack(oCreature)) + { + if(nCommand == AI_ALLY_IS_WOUNDED) + { + if(ai_TryHealing(oCreature, oCommander)) return; + } + else if(nCommand == AI_ALLY_IS_DISEASED || + nCommand == AI_ALLY_IS_POISONED || + nCommand == AI_ALLY_IS_WEAK) + { + if(ai_HealSickness(oCreature, oCommander, oMaster, nCommand)) return; + } + // A friend sees an enemy. If we are not in combat lets seek them out too! + else if(nCommand == AI_ALLY_SEES_AN_ENEMY || + nCommand == AI_ALLY_HEARD_AN_ENEMY) + { + if(AI_DEBUG) ai_Debug("0i_associates", "282", GetName(oCreature) + " receives notice that " + + GetName(oCommander) + " has seen1/heard2(" + IntToString(nCommand) + " an enemy: " + + GetName(GetLocalObject(oCommander, AI_MY_TARGET)) + "!"); + ai_ReactToAssociate(oCreature, oCommander, FALSE); + return; + } + // A friend is in combat. Make some checks to see if we should help. + else if(nCommand == AI_ALLY_ATKED_BY_WEAPON || + nCommand == AI_ALLY_ATKED_BY_SPELL) + { + if(AI_DEBUG) ai_Debug("0i_associates", "291", GetName(oCreature) + " receives notice that " + + GetName(oCommander) + " was attacked by an enemy!" + + GetName(GetLocalObject(oCommander, AI_MY_TARGET)) + "!"); + ai_ReactToAssociate(oCreature, oCommander, FALSE); + return; + } + else if(nCommand == AI_ALLY_IS_DEAD) + { // Nothing at the moment. + if(AI_DEBUG) ai_Debug("0i_associates", "298", GetName(oCreature) + " receives notice that " + + GetName(oCommander) + " has died!"); + return; + } + } + switch(nCommand) + { + case ASSOCIATE_COMMAND_MASTERATTACKEDOTHER: + { + if(AI_DEBUG) ai_Debug("0i_associate", "307", GetName(oMaster) + " has attacked!"); + if(ai_CanIAttack(oCreature)) + { + if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound(oCreature); + else ai_FindTheEnemy(oCreature, oCommander, ai_GetAttackedTarget(oCommander, TRUE, TRUE), FALSE); + } + return; + } + // Master tried to open a door or chest that is locked. + case ASSOCIATE_COMMAND_MASTERFAILEDLOCKPICK: + { + // In command mode we let the player tell us what to do. + if(ai_CanIAttack(oCreature)) + { + object oLock = ai_GetNearestLockedObject(oMaster); + //Check and see if our master want's us to open locks. + if(ai_GetAIMode(oCreature, AI_MODE_PICK_LOCKS) || + ai_GetAIMode(oCreature, AI_MODE_BASH_LOCKS)) + { + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_AttemptToByPassLock(oCreature, oLock); + } + } + return; + } + // Master saw a trap. + case ASSOCIATE_COMMAND_MASTERSAWTRAP: + { + // In command mode we let the player tell us what to do. + if(ai_CanIAttack(oCreature)) + { + object oTrap = GetLastTrapDetected(oMaster); + // Sometimes GetLastTrapDetected seems to fail. + if(oTrap == OBJECT_INVALID) oTrap = GetNearestTrapToObject(oMaster, TRUE); + //Check and see if our master want's us to disarm the trap. + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE); + SetTrapDetectedBy(oTrap, oCreature); + ai_ReactToTrap(oCreature, oTrap); + } + return; + } + // Menu used by a player to toggle henchmans search on and off. + case ASSOCIATE_COMMAND_TOGGLESEARCH: + { + int bTurnOn = !ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH); + string sAssociateType = ai_GetAssociateType(oMaster, oCreature); + ai_Philos_SetSearch(oMaster, oCreature, sAssociateType, bTurnOn); + return; + } + // Menu used by a player to toggle henchmans stealth on and off. + case ASSOCIATE_COMMAND_TOGGLESTEALTH: + { + int bTurnOn = !ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH); + string sAssociateType = ai_GetAssociateType(oMaster, oCreature); + ai_Philos_SetStealth(oMaster, oCreature, sAssociateType, bTurnOn); + return; + } + // Menu used by a player to have the henchman try to bypass the nearest lock. + case ASSOCIATE_COMMAND_PICKLOCK: + { + ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE); + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_SetAIMode(oCreature, AI_MODE_FOLLOW, FALSE); + object oLock = ai_GetNearestLockedObject(oMaster); + // Clear locked variable incase we tried already. + string sID = ObjectToString(oCreature); + SetLocalInt(oLock, "AI_LOCKED_" + sID, FALSE); + ai_AttemptToByPassLock(oCreature, oLock); + aiSaveAssociateModesToDb(oMaster, oCreature); + return; + } + // Menu used by a player to have the henchman try to disarm the nearest trap. + case ASSOCIATE_COMMAND_DISARMTRAP: + { + ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE); + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_SetAIMode(oCreature, AI_MODE_FOLLOW, FALSE); + object oTrap = GetNearestTrapToObject(oMaster); + // Clear trapped variable incase we tried already. + string sID = ObjectToString(oCreature); + ai_ReactToTrap(oCreature, oTrap, TRUE); + aiSaveAssociateModesToDb(oMaster, oCreature); + return; + } + // Menu used by a player to open a henchmans inventory to give, move, or take. + case ASSOCIATE_COMMAND_INVENTORY: + { + if(AI_OPEN_INVENTORY) + { + ai_HaveCreatureSpeak(oCreature, 4, ":29:46:35:"); + OpenInventory(oCreature, oCommander); + } + // Can't look at an associate's inventory. + else + { + ai_HaveCreatureSpeak(oCreature, 6, ":47:30:36:8:48:"); + ai_SendMessages("You cannot open " + GetName(oCreature) + "'s inventory.", AI_COLOR_GRAY, oMaster); + } + return; + } + case ASSOCIATE_COMMAND_LEAVEPARTY: + { + if(AI_REMOVE_HENCHMAN_ON) + { + ai_ClearCreatureActions(); + ai_FireHenchman (GetPCSpeaker(), oCreature); + PlayVoiceChat (VOICE_CHAT_GOODBYE, oCreature); + } + } + } + } +} +void ai_PassActionToAssociates(object oCreature, int nAction, int bStatus = TRUE) +{ + int nAssociateType; + object oAssociate; + for(nAssociateType = 2; nAssociateType < 6; nAssociateType ++) + { + oAssociate = GetAssociate(nAssociateType); + if(oAssociate != OBJECT_INVALID) SetActionMode(oAssociate, nAction, bStatus); + } +} +void ai_PassToAssociate(object oAssociate, int nAIMode, int bStatus) +{ + ai_ClearCreatureActions(TRUE); + ai_SetAIMode(oAssociate, nAIMode, bStatus); +} +void ai_PassAIModeToAssociates(object oAssociate, int nAIMode, int bStatus = TRUE) +{ + ai_SetAIMode(oAssociate, nAIMode, bStatus); + int nAssociateType; + object oAssoc; + for(nAssociateType = 2; nAssociateType < 6; nAssociateType ++) + { + oAssoc = GetAssociate(nAssociateType, oAssociate); + if(oAssoc != OBJECT_INVALID) AssignCommand(oAssoc, ai_PassToAssociate(oAssoc, nAIMode, bStatus)); + } +} +void ai_SetAssociateAIScript(object oCreature, int bCheckTacticScripts = TRUE) +{ + string sCombatAI; + object oMaster = GetMaster(); + if(ai_GetIsCharacter(oMaster)) + { + string sAssociateType = ai_GetAssociateType(oMaster, oCreature); + json jAIData = ai_GetAssociateDbJson(oMaster, sAssociateType, "aidata"); + sCombatAI = JsonGetString(JsonArrayGet(jAIData, 8)); + } + else sCombatAI = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + int nAssociateType = GetAssociateType(oCreature); + if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR && sCombatAI == "") + { + sCombatAI = "ai_a_default"; + } + else if(sCombatAI == "ai_coward") + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, sCombatAI); + return; + } + else if(bCheckTacticScripts && GetLocalInt(GetModule(), AI_RULE_AMBUSH)) + { + // They should have a skill ranks equal to their level + 1 to use a special AI. + int nSkillNeeded = GetHitDice(oCreature) + 1; + if(sCombatAI == "" || sCombatAI == "ai_a_ambusher") + { + // Ambusher: requires either Improved Invisibility or Invisibility. + if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oCreature) || + GetHasSpell(SPELL_INVISIBILITY, oCreature)) + { + int bCast = ai_TryToCastSpell(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature); + if(!bCast) bCast = ai_TryToCastSpell(oCreature, SPELL_INVISIBILITY, oCreature); + if(bCast) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_ambusher"); + return; + } + } + // Ambusher: Requires a Hide and Move silently skill equal to your level + 1. + else if(GetSkillRank(SKILL_HIDE, oCreature) >= nSkillNeeded && + GetSkillRank(SKILL_MOVE_SILENTLY, oCreature) >= nSkillNeeded) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_ambusher"); + return; + } + } + // Defensive : requires Parry skill equal to your level or Expertise. + else if(sCombatAI == "ai_a_defensive" || + (sCombatAI == "" && + (GetSkillRank(SKILL_PARRY, oCreature) >= nSkillNeeded || + GetHasFeat(FEAT_EXPERTISE, oCreature) || + GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature)))) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_defensive"); + return; + } + else if(sCombatAI == "ai_cntrspell" || GetHasSpell(SPELL_LESSER_DISPEL, oCreature) || + GetHasSpell(SPELL_DISPEL_MAGIC, oCreature) || GetHasSpell(SPELL_GREATER_DISPELLING, oCreature)) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_cntrspell"); + return; + } + } + if(sCombatAI == "") + { + // Select the best ai for this henchmen based on class. + int nClass = GetClassByPosition(1, oCreature); + // If they have more than one class use the default ai. + if(GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID) sCombatAI = "ai_a_default"; + else if(nClass == CLASS_TYPE_BARBARIAN) sCombatAI = "ai_a_barbarian"; + else if(nClass == CLASS_TYPE_BARD) sCombatAI = "ai_a_bard"; + else if(nClass == CLASS_TYPE_CLERIC) sCombatAI = "ai_a_cleric"; + else if(nClass == CLASS_TYPE_DRUID) sCombatAI = "ai_a_druid"; + else if(nClass == CLASS_TYPE_FIGHTER) sCombatAI = "ai_a_fighter"; + else if(nClass == CLASS_TYPE_MONK) sCombatAI = "ai_a_monk"; + else if(nClass == CLASS_TYPE_PALADIN) sCombatAI = "ai_a_paladin"; + else if(nClass == CLASS_TYPE_RANGER) sCombatAI = "ai_a_ranger"; + else if(nClass == CLASS_TYPE_ROGUE) sCombatAI = "ai_a_rogue"; + else if(nClass == CLASS_TYPE_SORCERER) sCombatAI = "ai_a_sorcerer"; + else if(nClass == CLASS_TYPE_WIZARD) sCombatAI = "ai_a_wizard"; + //else if(nClass == CLASS_TYPE_ABERRATION) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_ANIMAL) sCombatAI = "ai_a_animal"; + //else if(nClass == CLASS_TYPE_CONSTRUCT) sCombatAI = "ai_a_animal"; + //else if(nClass == CLASS_TYPE_DRAGON) sCombatAI = "ai_a_dragon"; + //else if(nClass == CLASS_TYPE_ELEMENTAL) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_FEY) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_GIANT) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_HUMANOID) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_MAGICAL_BEAST) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_MONSTROUS) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_OOZE) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_OUTSIDER) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_UNDEAD) sCombatAI = "ai_a_default"; + //else if(nClass == CLASS_TYPE_VERMIN) sCombatAI = "ai_a_animal"; + else sCombatAI = "ai_a_default"; + } + if(AI_DEBUG) ai_Debug("0i_associates", "530", GetName(oCreature) + " is setting AI to " + sCombatAI); + SetLocalString(oCreature, AI_COMBAT_SCRIPT, sCombatAI); + SetLocalString(oCreature, AI_DEFAULT_SCRIPT, sCombatAI); +} +int ai_CanISpeak (object oCreature) +{ + int nRace = GetRacialType (oCreature); + if (nRace == RACIAL_TYPE_ANIMAL || nRace == RACIAL_TYPE_BEAST || + nRace == RACIAL_TYPE_CONSTRUCT || nRace == RACIAL_TYPE_OOZE) return FALSE; + return (GetAbilityScore (oCreature, ABILITY_INTELLIGENCE) > 7); +} +void ai_FireHenchman(object oPC, object oHenchman) +{ + if(oPC == OBJECT_INVALID || oHenchman == OBJECT_INVALID) return; + // Now double-check that this is actually our master + if(GetMaster(oHenchman) != oPC) return; + // Turn off stealth mode + SetActionMode(oHenchman, ACTION_MODE_STEALTH, FALSE); + // Remove the henchman + RemoveHenchman (oPC, oHenchman); + ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER); +} +void ai_HenchmanCastDefensiveSpells (object oCreature, object oPC) +{ + ai_CastBuffs(oCreature, 3, 0, oPC); +} +int ai_CheckForCombat(object oCreature, int bMonster) +{ + object oEnemy = ai_GetNearestEnemy(oCreature, 1, 7, 7, 7, 5, TRUE); + //object oEnemy = ai_GetNearestEnemy(oCreature, 1, -1, -1, -1, -1, TRUE); + if(AI_DEBUG) ai_Debug("0i_associate", "586", "Checking for Combat: oEnemy is " + GetName(oEnemy) + + " Distance: " + FloatToString(GetDistanceBetween(oEnemy, oCreature), 0, 2)); + if(oEnemy != OBJECT_INVALID) + { + float fPerceptionDistance, fDistance; + if(bMonster) + { + fDistance = GetDistanceBetween(oCreature, oEnemy); + fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE); + } + else + { + // We want to use the distance between the PC and target not us. + object oMaster = GetMaster(); + if(oMaster != OBJECT_INVALID) fDistance = GetDistanceBetween(oMaster, oEnemy); + else fDistance = GetDistanceBetween(oCreature, oEnemy); + fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0; + } + if(fDistance < fPerceptionDistance) + { + ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:"); + SetLocalObject (oCreature, AI_MY_TARGET, oEnemy); + SpeakString(AI_I_SEE_AN_ENEMY, TALKVOLUME_SILENT_TALK); + if(bMonster) ai_StartMonsterCombat(oCreature); + else if(ai_CanIAttack(oCreature)) ai_StartAssociateCombat(oCreature); + return TRUE; + } + } + return FALSE; +} +void ai_AssociateEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception) +{ + if(!ai_CanIAttack(oCreature)) return; + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("0i_associates", "775", "Our current action: " + IntToString(nAction)); + switch(nAction) + { + // These actions are uninteruptable. + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_COUNTERSPELL : return; + // Might be doing a special action that is not a defined action. + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("0i_associate", "761", "Doing a special action (nCombatWait): " + IntToString(nCombatWait)); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + } + // We need to reevaluate combat during these actions when we see a new enemy. + //case ACTION_ATTACKOBJECT : + //case ACTION_MOVETOPOINT : + } + if(ai_GetIsInCombat(oCreature)) + { + object oTarget = ai_GetAttackedTarget(oCreature); + if(AI_DEBUG) ai_Debug("0i_associates", "775", "Should we recalculate our combat round? oTarget: " + GetName(oTarget) + + " oTarget Distance: " + FloatToString(GetDistanceBetween(oCreature, oTarget), 0, 2) + + " oLastPerceived Distance: " + FloatToString(GetDistanceBetween(oCreature, oLastPerceived), 0, 2)); + // If the LastPerceived is our target then don't recalculate. + if(oTarget == oLastPerceived) return; + // If we don't have a target or the lastperceived is closer than our + // target then recalculate. + if(oTarget == OBJECT_INVALID || + GetDistanceBetween(oCreature, oTarget) > GetDistanceBetween(oCreature, oLastPerceived)) + { + // We should clear any skill cooldowns that are at at max since that means they were skipped. + if(GetLocalInt(oCreature, "AI_EMPATHY_COOLDOWN") == AI_EMPATHY_COOLDOWN) + { DeleteLocalInt(oCreature, "AI_EMPATHY_COOLDOWN"); } + else if (GetLocalInt(oCreature, "AI_TAUNT_COOLDOWN") == AI_TAUNT_COOLDOWN) + { DeleteLocalInt(oCreature, "AI_EMPATHY_COOLDOWN"); } + ai_DoAssociateCombatRound(oCreature); + return; + } + // Lets only reevaluate combat if the new enemy is more powerful + // than the average enemies we already know about. + int nPower = ai_GetCharacterLevels(oLastPerceived) / 2; + int nEnemyPower = GetLocalInt(oCreature, AI_ENEMY_POWER) / (GetLocalInt(oCreature, AI_ENEMY_NUMBERS) + 1); + if(AI_DEBUG) ai_Debug("0i_associates", "797", " Is the new opponent more powerful? " + + GetName(oLastPerceived) + " nPower: " + IntToString(nPower) + + " nEnemyPower: " + IntToString(nEnemyPower)); + if(nEnemyPower < nPower) ai_DoAssociateCombatRound(oCreature); + return; + } + // Heard fires first, but Heard and Seen are both set at the same time. + // So lets skip the hearing code if they are also seen. + if(sPerception == AI_I_SEE_AN_ENEMY || GetObjectSeen(oLastPerceived, oCreature)) + { + // We are not in combat and we see the enemy so alert our allies! + ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:"); + SetLocalObject (oCreature, AI_MY_TARGET, oLastPerceived); + SpeakString(sPerception, TALKVOLUME_SILENT_TALK); + ai_StartAssociateCombat(oCreature); + } + else ai_FindTheEnemy(oCreature, oLastPerceived, oLastPerceived, FALSE); +} +void ai_MonsterEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception) +{ + if(!ai_CanIAttack(oCreature)) return; + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("0i_associates", "672", "nAction: " + IntToString(nAction)); + switch(nAction) + { + // These actions are uninteruptable. + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_COUNTERSPELL : return; + // Might be doing a special action that is not a defined action. + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("0i_associates", "683", "nCombatWait: " + IntToString(nCombatWait)); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + } + // We need to reevaluate combat during these actions when we see a new enemy. + //case ACTION_ATTACKOBJECT : + //case ACTION_MOVETOPOINT : + } + if(ai_GetIsInCombat(oCreature)) + { + object oTarget = ai_GetAttackedTarget(oCreature); + if(AI_DEBUG) ai_Debug("0i_associates", "697", "oTarget: " + GetName(oTarget) + + " oTarget Distance: " + FloatToString(GetDistanceBetween(oCreature, oTarget), 0, 2) + + " oLastPerceived Distance: " + FloatToString(GetDistanceBetween(oCreature, oLastPerceived), 0, 2)); + // If the LastPerceived is our target then don't recalculate. + if(oTarget == oLastPerceived) return; + // If we don't have a target or the lastperceived is closer than our + // target then recalculate. + if(oTarget == OBJECT_INVALID || + GetDistanceBetween(oCreature, oTarget) > GetDistanceBetween(oCreature, oLastPerceived)) + { + ai_DoMonsterCombatRound(oCreature); + return; + } + // Now only reevaluate combat if the new enemy is more powerful + // than the average enemies we already know about. + int nPower = ai_GetCharacterLevels(oLastPerceived) / 2; + int nEnemyPower = GetLocalInt(oCreature, AI_ENEMY_POWER) / (GetLocalInt(oCreature, AI_ENEMY_NUMBERS) + 1); + if(AI_DEBUG) ai_Debug("0i_associates", "714", GetName(oLastPerceived) + " nPower: " + IntToString(nPower) + + " nEnemyPower: " + IntToString(nEnemyPower)); + if(nEnemyPower < nPower) ai_DoMonsterCombatRound(oCreature); + return; + } + if(sPerception == AI_I_SEE_AN_ENEMY) + { + if(d100() < 34) + { + // We are not in combat so alert our allies! + ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:"); + } + SetLocalObject(oCreature, AI_MY_TARGET, oLastPerceived); + SpeakString(sPerception, TALKVOLUME_SILENT_TALK); + ai_StartMonsterCombat(oCreature); + } + else ai_FindTheEnemy(oCreature, oLastPerceived, oLastPerceived, TRUE); +} +void ai_CopyObjectVariables(object oOldObject, object oNewObject) +{ + json jObject = ObjectToJson(oOldObject, TRUE); + json jVarTable = GffGetList(jObject, "VarTable"); + string sVariable, sName; + int nIndex, nVarType; + json jVar = JsonArrayGet(jVarTable, nIndex); + while(JsonGetType(jVar) != JSON_TYPE_NULL) + { + sName = JsonGetString(GffGetString(jVar, "Name")); + nVarType = JsonGetInt(GffGetDword(jVar, "Type")); + if(nVarType == 1) SetLocalInt(oNewObject, sName, JsonGetInt(GffGetInt(jVar, "Value"))); + else if(nVarType == 2) SetLocalFloat(oNewObject, sName, JsonGetFloat(GffGetFloat(jVar, "Value"))); + else if(nVarType == 3) SetLocalString(oNewObject, sName, JsonGetString(GffGetString(jVar, "Value"))); + jVar = JsonArrayGet(jVarTable, ++nIndex); + } +} +//****************************************************************************** +//********************* Creature event scripts ********************************* +//****************************************************************************** + +void ai_OnRested(object oCreature) +{ + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_AFTER_REST)) + { + int nLevel = ai_GetCharacterLevels(oCreature); + float fDelay = StringToFloat(Get2DAString("restduration", "DURATION", nLevel)); + fDelay = (fDelay / 1000.0f) + 2.0f; + DelayCommand(fDelay, ai_HenchmanCastDefensiveSpells(oCreature, GetMaster())); + } +} + +//****************************************************************************** +//******************* Associate AI option scripts ****************************** +//****************************************************************************** +void ai_UpdateToolTipUI(object oPC, string sWindowID1, string sWindowID2, string sToolTipBind, string sText) +{ + int nMenuToken = NuiFindWindow(oPC, sWindowID1); + if(nMenuToken) NuiSetBind (oPC, nMenuToken, sToolTipBind, JsonString (sText)); + if(sWindowID2 != "") + { + int nWidgetToken = NuiFindWindow(oPC, sWindowID2); + if(nWidgetToken) NuiSetBind (oPC, nWidgetToken, sToolTipBind, JsonString (sText)); + } +} +void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType) +{ + float fAdjustment = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + fIncrement; + if(fAdjustment > 10.0) fAdjustment = 10.0; + else if(fAdjustment < 1.0) fAdjustment = 1.0; + SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, fAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 6, JsonFloat(fAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sName; + object oTarget = GetLocalObject(oAssociate, AI_FOLLOW_TARGET); + string sTarget; + if(oTarget != OBJECT_INVALID) sTarget = GetName(oTarget); + else + { + if(ai_GetIsCharacter(oAssociate)) sTarget = "nobody"; + else sTarget = GetName(oPC); + } + float fRange = fAdjustment + + StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate))); + string sRange = FloatToString(fRange, 0, 0); + if(oPC == oAssociate) + { + sName = " All associates"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_follow_tooltip", sName + " enter follow mode "); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]"); + } + else + { + sName = " " + GetName(oAssociate); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_follow_tooltip", sName + " enter follow mode [" + sRange + " meters]"); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]"); + } +} +void ai_Ranged(object oPC, object oAssociate, string sAssociateType) +{ + //ai_ClearCreatureActions(); + if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED)) + { + ai_SendMessages(GetName(oAssociate) + " is using ranged combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ranged_tooltip", " Ranged On"); + ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, FALSE); + ai_EquipBestRangedWeapon(oAssociate); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is using melee combat only.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ranged_tooltip", " Ranged Off"); + ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, TRUE); + ai_EquipBestMeleeWeapon(oAssociate); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_EquipWeapons(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF)) + { + ai_SendMessages(GetName(oAssociate) + " will be equiping their best weapons.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_equip_weapon_tooltip", " Equiping Best Weapons On"); + ai_SetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will not equip their best weapons.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_equip_weapon_tooltip", " Equiping Best Weapons Off"); + ai_SetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Search(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH)) + { + ai_SendMessages(GetName(oAssociate) + " is turning search off.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode Off"); + SetActionMode(oAssociate, ACTION_MODE_DETECT, FALSE); + ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is turning search on.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode On"); + SetActionMode(oAssociate, ACTION_MODE_DETECT, TRUE); + ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Stealth(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH)) + { + ai_SendMessages(GetName(oAssociate) + " is turning stealth off.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode Off"); + SetActionMode(oAssociate, ACTION_MODE_STEALTH, FALSE); + ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is turning stealth on.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode On"); + SetActionMode(oAssociate, ACTION_MODE_STEALTH, TRUE); + ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_OpenDoor(object oPC, object oAssociate, string sAssociateType) +{ + string sRange = FloatToString(GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE), 0, 0); + if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS)) + { + ai_SendMessages(GetName(oAssociate) + " is turning open doors off.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", " Open Doors Off [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_OPEN_DOORS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is turning open doors on.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", " Open Doors On [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_OPEN_DOORS, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Locks(object oPC, object oAssociate, string sAssociateType, int nMode) +{ + string sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE), 0, 0); + if(nMode == 1) + { + if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS)) + { + ai_SendMessages(GetName(oAssociate) + " will stop picking locks.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", " Pick Locks Off [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_PICK_LOCKS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will now pick locks.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", " Pick Locks On [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_PICK_LOCKS, TRUE); + } + } + else if(nMode == 2) + { + if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) + { + ai_SendMessages(GetName(oAssociate) + " will stop bashing.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", " Bash Locks Off [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_BASH_LOCKS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will now bash things.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", " Bash Locks On [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_BASH_LOCKS, TRUE); + } + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Traps(object oPC, object oAssociate, string sAssociateType) +{ + string sRange = FloatToString(GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE), 0, 0); + if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS)) + { + ai_SendMessages(GetName(oAssociate) + " will stop disarming traps.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", " Disable Traps Off [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_DISARM_TRAPS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will now disarm traps.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", " Disable Traps On [" + sRange + " meters]"); + ai_SetAIMode(oAssociate, AI_MODE_DISARM_TRAPS, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_ReduceSpeech(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK)) + { + ai_SendMessages(GetName(oAssociate) + " will increase speech.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_quiet_tooltip", " Reduced Speech Off"); + ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will reduce speech.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_quiet_tooltip", " Reduced Speech On"); + ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_UseOffensiveMagic(object oPC, object oAssociate, int bDefensive, int bOffensive, string sAssociateType) +{ + if(bOffensive) + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING)) + { + ai_SendMessages(GetName(oAssociate) + " has stopped using offensive magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is now using offensive magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic On"); + ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, TRUE); + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, FALSE); + } + else if(bDefensive) + { + if(ai_GetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING)) + { + ai_SendMessages(GetName(oAssociate) + " has stopped using defensive magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " is now using defensive magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic On"); + ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, TRUE); + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, FALSE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_UseMagic(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC)) + { + ai_SendMessages(GetName(oAssociate) + " is now using magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_tooltip", " Magic On"); + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " has stopped using magic in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_tooltip", " Magic Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_UseMagicItems(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS)) + { + ai_SendMessages(GetName(oAssociate) + " is now using magic items in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_items_tooltip", " Magic Items On"); + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " has stopped using magic items in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_items_tooltip", " Magic Items Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Loot(object oPC, object oAssociate, string sAssociateType) +{ + int bLooting = !ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS); + string sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE), 0, 0); + string sMessage, sText; + if(bLooting) + { + sMessage = " is picking up items."; + sText = " Looting On [" + sRange + " meters]"; + } + else + { + sMessage = " is not picking up items."; + sText = " Looting Off [" + sRange + " meters]"; + } + ai_SendMessages(GetName(oAssociate) + sMessage, AI_COLOR_YELLOW, oPC); + ai_SetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS, bLooting); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_loot_tooltip", sText); + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Spontaneous(object oPC, object oAssociate, string sAssociateType) +{ + int bSpontaneous = !ai_GetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE); + string sMessage, sText; + + if(bSpontaneous) + { + sMessage = " has stop casting spontaneous healing spells."; + sText = " Spontaneous casting Off"; + } + else + { + sMessage = " will now cast spontaneous healing spells."; + sText = " Spontaneous casting On"; + } + ai_SendMessages(GetName(oAssociate) + sMessage, AI_COLOR_YELLOW, oPC); + ai_SetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE, bSpontaneous); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_spontaneous_tooltip", sText); + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_MagicIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType) +{ + int nAdjustment = GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT) + nIncrement; + if(nAdjustment > 100) nAdjustment = 100; + else if(nAdjustment < -100) nAdjustment = -100; + SetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT, nAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 0, JsonInt(nAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sMagic = IntToString(nAdjustment); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_level_tooltip", " Magic Level [" + sMagic + "]"); +} +void ai_LootRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType) +{ + float fAdjustment = GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE) + fIncrement; + if(fAdjustment > 40.0) fAdjustment = 40.0; + else if(fAdjustment < 0.0) fAdjustment = 0.0; + SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, fAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 3, JsonFloat(fAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sRange = FloatToString(fAdjustment, 0, 0); + string sLoot = " Looting Off [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS)) sLoot = " Looting On [" + sRange + " meters]"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_loot_tooltip", sLoot); +} +void ai_LockRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType) +{ + float fAdjustment = GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE) + fIncrement; + if(fAdjustment > 40.0) fAdjustment = 40.0; + else if(fAdjustment < 0.0) fAdjustment = 0.0; + SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, fAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 4, JsonFloat(fAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sRange = FloatToString(fAdjustment, 0, 0); + string sPick = " Pick Locks Off [" + sRange + " meters]"; + string sBash = " Bash Off [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS)) sPick = " Pick Locks On [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) sBash = " Bash On [" + sRange + " meters]"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", sPick); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", sBash); +} +void ai_TrapRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType) +{ + float fAdjustment = GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE) + fIncrement; + if(fAdjustment > 40.0) fAdjustment = 40.0; + else if(fAdjustment < 0.0) fAdjustment = 0.0; + SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, fAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 5, JsonFloat(fAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sRange = FloatToString(fAdjustment, 0, 0); + string sText = " Disable Traps Off [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS)) sText = " Disable Traps On [" + sRange + " meters]"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", sText); +} +void ai_OpenDoorIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType) +{ + float fAdjustment = GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE) + fIncrement; + if(fAdjustment > 40.0) fAdjustment = 40.0; + else if(fAdjustment < 0.0) fAdjustment = 0.0; + SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, fAdjustment); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jAIData = JsonArraySet(jAIData, 9, JsonFloat(fAdjustment)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + string sRange = FloatToString(fAdjustment, 0, 0); + string sText = " Open Doors Off [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS)) sText = " Open Doors On [" + sRange + " meters]"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", sText); +} +void ai_SaveAIScript(object oPC, object oAssociate, int nToken) +{ + string sScript = JsonGetString(NuiGetBind(oPC, nToken, "txt_ai_script")); + string sOldScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + if(GetStringLeft(sScript, 5) != "ai_a_") ai_SendMessages(sScript + " does not have correct prefix it must have ai_a_ for associates! Did not change AI script.", AI_COLOR_RED, oPC); + else if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "") + { + ai_SendMessages(sScript + " not found by ResMan! This is not a valid AI script.", AI_COLOR_RED, oPC); + } + else if(sScript != sOldScript) + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + if(JsonGetType(JsonArrayGet(jAIData, 8)) == JSON_TYPE_NULL) jAIData = JsonArrayInsert(jAIData, JsonString(sScript)); + else jAIData = JsonArraySet(jAIData, 8, JsonString(sScript)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + ai_SendMessages(GetName(oAssociate) + " is now using " + sScript + " AI script!", AI_COLOR_GREEN, oPC); + } + else ai_SendMessages(GetName(oAssociate) + " is already using this script! Did not change AI script.", AI_COLOR_RED, oPC); +} +void ai_Buff_Button(object oPC, object oAssociate, int nOption, string sAssociateType) +{ + if(nOption == 0) + { + int bRestBuff = !ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST); + ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST, bRestBuff); + if(bRestBuff) + { + ai_SendMessages(GetName(oAssociate) + " will cast long buffs after resting.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_buff_rest_tooltip", " [On] Turn buffing after resting off."); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will not cast long buffs after resting.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_buff_rest_tooltip", " [Off] Turn buffing after resting on."); + } + aiSaveAssociateModesToDb(oPC, oAssociate); + } + else + { + if(!GetIsPossessedFamiliar(oAssociate)) + { + object oEnemy = GetNearestEnemy(oAssociate); + //ai_Debug("0e_nui", "865", "oEnemy: " + GetName(oEnemy) + " fDistance: " + + // FloatToString(GetDistanceBetween(oAssociate, oEnemy), 0, 2)); + if(GetDistanceBetween(oAssociate, oEnemy) > 30.0 || + oEnemy == OBJECT_INVALID) + { + ai_CastBuffs(oAssociate, nOption, 0, oPC); + } + else ai_SendMessages("You cannot buff while there are enemies nearby.", AI_COLOR_RED, oPC); + } + else ai_SendMessages("You cannot buff while possessing your familiar.", AI_COLOR_RED, oPC); + } +} +void ai_Heal_Button(object oPC, object oAssociate, int nIncrement, string sVar, string sAssociateType) +{ + int nHeal = GetLocalInt(oAssociate, sVar); + if(nIncrement > 0 && nHeal > 100 - nIncrement) nHeal = 100 - nIncrement; + if(nIncrement < 0 && nHeal < abs(nIncrement)) nHeal = abs(nIncrement); + nHeal += nIncrement; + SetLocalInt(oAssociate, sVar, nHeal); + string sHeal = IntToString(nHeal); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + if(sVar == AI_HEAL_OUT_OF_COMBAT_LIMIT) + { + string sText = " Will heal at or below [" + sHeal + "%] health out of combat"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heal_out_tooltip", sText); + jAIData = JsonArraySet(jAIData, 1, JsonInt(nHeal)); + } + else if(sVar == AI_HEAL_IN_COMBAT_LIMIT) + { + string sText = " Will heal at or below [" + sHeal + "%] health in combat"; + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heal_in_tooltip", sText); + jAIData = JsonArraySet(jAIData, 2, JsonInt(nHeal)); + } + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); +} +void ai_Heal_OnOff(object oPC, object oAssociate, string sAssociateType, int nMode) +{ + string sText, sText2; + if(nMode == 1) + { + if(ai_GetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF)) + { + ai_SetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF, FALSE); + sText = " Self healing On"; + sText2 = " will now use healing on themselves."; + } + else + { + ai_SetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF, TRUE); + sText = " Self healing Off"; + sText2 = " will stop using healing on themselves."; + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heals_onoff_tooltip", sText); + } + else + { + if(ai_GetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF)) + { + ai_SetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF, FALSE); + sText = " Party healing On"; + sText2 = " will now use healing on party members."; + } + else + { + ai_SetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF, TRUE); + sText = " Party healing Off"; + sText2 = " will stop using healing on party members."; + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_healp_onoff_tooltip", sText); + } + ai_SendMessages(GetName(oAssociate) + sText2, AI_COLOR_YELLOW, oPC); + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Cure_OnOff(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF)) + { + ai_SendMessages(GetName(oAssociate) + " will now cast cure spells.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cure_onoff_tooltip", " Cast Cure Spells On"); + ai_SetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will stop casting cure spells.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cure_onoff_tooltip", " Cast Cure Spells Off"); + ai_SetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Ignore_Associates(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES)) + { + ai_SendMessages(GetName(oAssociate) + " will stop ignoring henchman's associates and enemy associates.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_assoc_tooltip", " Ignore Enemy Associates Off"); + ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will now ignore henchman's associates and enemy associates.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_assoc_tooltip", " Ignore Enemy Associates On"); + ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_Ignore_Traps(object oPC, object oAssociate, string sAssociateType) +{ + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS)) + { + ai_SendMessages(GetName(oAssociate) + " will stop ignoring traps on the floor and will stop moving when one is seen.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_traps_tooltip", " Ignore Floor Traps Off"); + ai_SetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS, FALSE); + } + else + { + ai_SendMessages(GetName(oAssociate) + " will now ignore traps on the floor and will continue with their actions.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_traps_tooltip", " Ignore Floor Traps On"); + ai_SetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS, TRUE); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_FollowTarget(object oPC, object oAssociate) +{ + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate); + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_FOLLOW_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_Original_Guard() +{ + ResetHenchmenState(); + //Companions will only attack the Masters Last Attacker + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + object oMaster = GetMaster(); + object oLastAttacker = GetLastHostileActor(oMaster); + // * for some reason this is too often invalid. still the routine + // * works corrrectly + SetLocalInt(OBJECT_SELF, "X0_BATTLEJOINEDMASTER", TRUE); + HenchmenCombatRound(oLastAttacker); + ai_SendMessages(GetName(OBJECT_SELF) + " is now guarding you!", AI_COLOR_YELLOW, oMaster); +} +void ai_Original_Follow() +{ + ResetHenchmenState(); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + DelayCommand(2.5, VoiceCanDo()); + object oMaster = GetMaster(); + ActionForceFollowObject(oMaster, GetFollowDistance()); + SetAssociateState(NW_ASC_IS_BUSY); + DelayCommand(5.0, SetAssociateState(NW_ASC_IS_BUSY, FALSE)); + ai_SendMessages(GetName(OBJECT_SELF) + " is now following You!", AI_COLOR_YELLOW, oMaster); +} +void ai_Original_StandGround() +{ + SetAssociateState(NW_ASC_MODE_STAND_GROUND); + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE); + DelayCommand(2.0, VoiceCanDo()); + ActionAttack(OBJECT_INVALID); + ClearActions(CLEAR_X0_INC_HENAI_RespondToShout1); + ai_SendMessages(GetName(OBJECT_SELF) + " is now standing their ground!", AI_COLOR_YELLOW, GetMaster()); +} +void ai_Original_AttackNearest() +{ + ResetHenchmenState(); + SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE); + SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE); + DetermineCombatRound(); + // * bonus feature. If master is attacking a door or container, issues VWE Attack Nearest + // * will make henchman join in on the fun + object oMaster = GetMaster(); + object oTarget = GetAttackTarget(oMaster); + if (GetIsObjectValid(oTarget) == TRUE) + { + if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE || GetObjectType(oTarget) == OBJECT_TYPE_DOOR) + { + ActionAttack(oTarget); + } + } + ai_SendMessages(GetName(OBJECT_SELF) + " is now in normal mode!", AI_COLOR_YELLOW, oMaster); +} +void ai_Original_SetSearch(object oAssociate, int bTurnOn) +{ + if(GetRacialType(oAssociate) != RACIAL_TYPE_ELF) SetActionMode(oAssociate, ACTION_MODE_DETECT, bTurnOn); +} +void ai_Original_SetStealth(object oAssociate, int bTurnOn) +{ + SetActionMode(oAssociate, ACTION_MODE_STEALTH, bTurnOn); +} +void ai_Philos_Guard(object oMaster, object oCreature) +{ + ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, TRUE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI); + ai_HighlightWidgetMode(oMaster, oCreature, nToken); + if(!ai_GetIsBusy(oCreature) && ai_GetIsInCombat(oCreature)) + { + object oLastAttacker = GetLastHostileActor(oMaster); + if(oLastAttacker != OBJECT_INVALID) ai_DoAssociateCombatRound(oCreature, oLastAttacker); + else AssignCommand(oCreature, ActionMoveToObject(oMaster, TRUE)); + } + ai_SendMessages(GetName(oCreature) + " is now guarding you!", AI_COLOR_YELLOW, oMaster); + aiSaveAssociateModesToDb(oMaster, oCreature); +} +void ai_Philos_Follow(object oMaster) +{ + object oCreature = OBJECT_SELF; + ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, TRUE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI); + ai_HighlightWidgetMode(oMaster, oCreature, nToken); + aiSaveAssociateModesToDb(oMaster, oCreature); + // To follow we probably should be running and not searching or hiding. + if(GetDetectMode(oCreature) && !GetHasFeat(FEAT_KEEN_SENSE, oCreature)) SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + if(GetStealthMode(oCreature)) SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + ai_PassActionToAssociates(oCreature, ACTION_FOLLOW); + if(ai_IsInCombatRound(oCreature)) ai_ClearCombatState(oCreature); + ai_ClearCreatureActions(TRUE); + object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oMaster; + ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oCreature)); + ai_SendMessages(GetName(oCreature) + " is now following " + GetName(oTarget) + "!", AI_COLOR_YELLOW, oMaster); +} +void ai_Philos_StandGround(object oMaster) +{ + object oCreature = OBJECT_SELF; + ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, TRUE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE); + ai_PassActionToAssociates(oCreature, ACTION_FOLLOW, FALSE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI); + ai_HighlightWidgetMode(oMaster, oCreature, nToken); + if(ai_IsInCombatRound(oCreature)) + { + ai_ClearCombatState(oCreature); + DeleteLocalObject(oCreature, AI_ATTACKED_PHYSICAL); + DeleteLocalObject(oCreature, AI_ATTACKED_SPELL); + } + ai_ClearCreatureActions(TRUE); + ai_SendMessages(GetName(oCreature) + " is now standing their ground!", AI_COLOR_YELLOW, oMaster); + aiSaveAssociateModesToDb(oMaster, oCreature); +} +void ai_Philos_AttackNearest(object oMaster, object oCreature) +{ + ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, FALSE); + ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE); + ai_PassActionToAssociates(oCreature, ACTION_FOLLOW, FALSE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI); + ai_HighlightWidgetMode(oMaster, oCreature, nToken); + // Removes any targets the PC may have given the associate. + DeleteLocalObject(oCreature, AI_PC_LOCKED_TARGET); + // This resets a henchmens failed Moral save in combat. + string sScript = GetLocalString(oCreature, AI_COMBAT_SCRIPT); + if(sScript == "ai_coward") + { + sScript = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + SetLocalString(oCreature, AI_COMBAT_SCRIPT, sScript); + } + if(!ai_GetIsBusy(oCreature)) + { + object oEnemy = ai_GetNearestEnemy(oCreature, 1, 7, 7); + if(oEnemy != OBJECT_INVALID && GetDistanceBetween(oCreature, oEnemy) < AI_RANGE_BATTLEFIELD) + { + ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:"); + // If master is attacking a target we will attack them too! + if(!ai_GetIsInCombat(oCreature)) ai_StartAssociateCombat(oCreature); + object oTarget = ai_GetAttackedTarget(oMaster); + if(oTarget == OBJECT_INVALID) ai_DoAssociateCombatRound(oCreature); + else ai_DoAssociateCombatRound(oCreature, oTarget); + } + else + { + object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oMaster; + AssignCommand(oCreature, ActionMoveToObject(oMaster, TRUE, ai_GetFollowDistance(oCreature))); + } + } + ai_SendMessages(GetName(oCreature) + " is now in normal mode!", AI_COLOR_YELLOW, oMaster); + aiSaveAssociateModesToDb(oMaster, oCreature); +} +void ai_Philos_SetSearch(object oMaster, object oCreature, string sAssociateType, int bTurnOn) +{ + if(bTurnOn) + { + ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH, TRUE); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, TRUE); + //ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, TRUE); + ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode On"); + } + else + { + ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH, FALSE); + SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, FALSE); + //ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, FALSE); + ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode Off"); + } + aiSaveAssociateModesToDb(oMaster, oCreature); +} +void ai_Philos_SetStealth(object oMaster, object oCreature, string sAssociateType, int bTurnOn) +{ + if(bTurnOn) + { + ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, TRUE); + ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode On"); + } + else + { + ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH, FALSE); + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, FALSE); + //ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, FALSE); + ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode Off"); + } + aiSaveAssociateModesToDb(oMaster, oCreature); +} +void ai_DoCommand(object oPC, object oAssociate, int nCommand) +{ + int nIndex = 1; + if(oPC == oAssociate) + { + if(nCommand == 1) // Guard PC. + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Guard()); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Guard()); + } + } + // Use Philos AI commands. + else + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) ai_Philos_Guard(oPC, oAssociate); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) ai_Philos_Guard(oPC, oAssociate); + } + } + } + else if(nCommand == 2) // Follow PC. + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Follow()); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Follow()); + } + } + // Use Philos AI commands. + else + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_Follow(oPC)); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_Follow(oPC)); + } + } + } + else if(nCommand == 3) // Standground. + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_StandGround()); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_StandGround()); + } + } + // Use Philos AI commands. + else + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_StandGround(oPC)); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_StandGround(oPC)); + } + } + } + else if(nCommand == 4) // Normal mode - i.e. Attack nearest. + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_AttackNearest()); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_AttackNearest()); + } + } + // Use Philos AI commands. + else + { + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) ai_Philos_AttackNearest(oPC, oAssociate); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) ai_Philos_AttackNearest(oPC, oAssociate); + } + } + } + if(nCommand == 5) // All associates toggle search mode + { + int bTurnOn = !ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_SEARCH); + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + ai_Original_SetSearch(oPC, bTurnOn); + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) ai_Original_SetSearch(oAssociate, bTurnOn); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) ai_Original_SetSearch(oAssociate, bTurnOn); + } + } + else + { + ai_Philos_SetSearch(oPC, oPC, "pc", bTurnOn); + string sAssociateType; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) + { + sAssociateType = ai_GetAssociateType(oPC, oAssociate); + ai_Philos_SetSearch(oPC, oAssociate, sAssociateType, bTurnOn); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) + { + sAssociateType = ai_GetAssociateType(oPC, oAssociate); + ai_Philos_SetSearch(oPC, oAssociate, sAssociateType, bTurnOn); + } + } + } + if(bTurnOn) + { + ai_SendMessages("Everyone is now in search mode!", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_search_tooltip", " Everyone leave search mode"); + } + else + { + ai_SendMessages("Everyone has left search mode!", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_search_tooltip", " Everyone enter search mode"); + } + } + if(nCommand == 6) // All associate use stealth mode + { + int bTurnOn = !ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_STEALTH); + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + ai_Original_SetStealth(oPC, bTurnOn); + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) ai_Original_SetStealth(oAssociate, bTurnOn); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) ai_Original_SetStealth(oAssociate, bTurnOn); + } + } + else + { + ai_Philos_SetStealth(oPC, oPC, "pc", bTurnOn); + string sAssociateType; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) + { + sAssociateType = ai_GetAssociateType(oPC, oAssociate); + ai_Philos_SetStealth(oPC, oAssociate, sAssociateType, bTurnOn); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) + { + sAssociateType = ai_GetAssociateType(oPC, oAssociate); + ai_Philos_SetStealth(oPC, oAssociate, sAssociateType, bTurnOn); + } + } + } + if(bTurnOn) + { + ai_SendMessages("Everyone is now in stealth mode.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_stealth_tooltip", " Everyone leave stealth mode"); + } + else + { + ai_SendMessages("Everyone has left stealth mode.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_stealth_tooltip", " Everyone enter stealth mode"); + } + } + } + else + { + if(nCommand == 1) + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + AssignCommand(oAssociate, ai_Original_Guard()); + } + else ai_Philos_Guard(oPC, oAssociate); + } + else if(nCommand == 2) + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + AssignCommand(oAssociate, ai_Original_Follow()); + } + else AssignCommand(oAssociate, ai_Philos_Follow(oPC)); + } + else if(nCommand == 3) + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + AssignCommand(oAssociate, ai_Original_StandGround()); + } + else AssignCommand(oAssociate, ai_Philos_StandGround(oPC)); + } + else if(nCommand == 4) + { + // Not using Philos Henchman AI. Use vanilla commands. + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "") + { + AssignCommand(oAssociate, ai_Original_AttackNearest()); + } + else ai_Philos_AttackNearest(oPC, oAssociate); + } + } +} +void ai_Action(object oPC, object oAssociate) +{ + if(oPC == oAssociate) + { + DeleteLocalObject(oPC, "NW_ASSOCIATE_COMMAND"); + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION_ALL"); + ai_SendMessages("Select an action for the party.", AI_COLOR_YELLOW, oPC); + } + else + { + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate); + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION"); + ai_SendMessages("Select an action for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC); + } + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_AIScript(object oPC, object oAssociate, string sAssociateType, int nToken) +{ + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != "") + { + string sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + string sIcon = "ir_scommand"; + if(sScript == "ai_a_ambusher") + { + sScript = "ai_a_flanker"; + sIcon = "ir_invite"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using flanking tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Flanker: Attacks enemies engaged with allies"); + } + else if(sScript == "ai_a_flanker") + { + sScript = "ai_a_peaceful"; + sIcon = "ir_ignore"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using peaceful tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Peaceful: Avoids attacking any enemies if possible"); + } + else if(sScript == "ai_a_peaceful") + { + sScript = "ai_a_defensive"; + sIcon = "ir_knockdwn"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using defensive tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Defensive: Attacks then uses Expertise/Parry"); + } + else if(sScript == "ai_a_defensive") + { + sScript = "ai_a_ranged"; + sIcon = "ir_ranger"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using ranged tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Ranged: Attacks from range as much as possible"); + } + else if(sScript == "ai_a_ranged") + { + sScript = "ai_a_cntrspell"; + sIcon = "ir_dcaster"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using counter spell tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Counter Spell: Tries to counter enemy spells"); + } + else if(sScript == "ai_a_cntrspell") + { + DeleteLocalString(oAssociate, AI_DEFAULT_SCRIPT); + ai_SetAssociateAIScript(oAssociate, FALSE); + sScript = GetLocalString(oAssociate, AI_DEFAULT_SCRIPT); + ai_SendMessages(GetName(oAssociate) + " is now using default tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Default tactics: Using the creatures base AI script"); + } + else + { + sScript = "ai_a_ambusher"; + sIcon = "ir_rogue"; + SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript); + ai_SendMessages(GetName(oAssociate) + " is now using ambush tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Ambusher: Attacks from a hidden position"); + } + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_image", JsonString(sIcon)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_label", JsonString("Tactics: " + sScript)); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + if(JsonGetType(JsonArrayGet(jAIData, 8)) == JSON_TYPE_NULL) jAIData = JsonArrayInsert(jAIData, JsonString(sScript)); + else jAIData = JsonArraySet(jAIData, 8, JsonString(sScript)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + else + { + if(GetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, oAssociate)) + { + SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, TRUE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate); + ai_SendMessages(GetName(oAssociate) + " is now using coward tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using coward tactics"); + } + else if(GetCombatCondition(X0_COMBAT_FLAG_COWARDLY, oAssociate)) + { + SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, TRUE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate); + ai_SendMessages(GetName(oAssociate) + " is now using defensive tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using defensive tactics"); + } + else if(GetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, oAssociate)) + { + SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_RANGED, TRUE, oAssociate); + ai_SendMessages(GetName(oAssociate) + " is now using ranged tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ranged tactics"); + } + else if(GetCombatCondition(X0_COMBAT_FLAG_RANGED, oAssociate)) + { + SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate); + ai_SendMessages(GetName(oAssociate) + " is now using normal tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ambush tactics"); + } + else + { + SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, TRUE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate); + SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate); + ai_SendMessages(GetName(oAssociate) + " is now using ambush tactics in combat.", AI_COLOR_YELLOW, oPC); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ambush tactics"); + } + } +} +void ai_HavePCPlaceTrap(object oPC, object oAssociate) +{ + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate); + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_GET_TRAP"); + ai_SendMessages(GetName(oAssociate) + " select a trap to place.", AI_COLOR_YELLOW, oPC); + OpenInventory(oAssociate, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ITEM, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_JumpAssociateToPC(object oPC) +{ + ai_ClearCreatureActions(TRUE); + JumpToObject(oPC); +} +void ai_JumpToPC(object oPC, object oAssociate) +{ + int nAssociateType, nHenchman, nHenchAssociate; + object oHenchman, oHenchmanAssociate; + if(oPC != oAssociate) + { + if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) + { + for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++) + { + oHenchmanAssociate = GetAssociate(nHenchAssociate, oHenchman, 1); + if(oHenchmanAssociate != OBJECT_INVALID) + { + AssignCommand(oHenchmanAssociate, ai_JumpAssociateToPC(oPC)); + } + } + AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC)); + } + else AssignCommand(oAssociate, ai_JumpAssociateToPC(oPC)); + return; + } + for(nAssociateType = 1; nAssociateType <= 5; nAssociateType++) + { + if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) + { + for(nHenchman = 1; nHenchman <= AI_MAX_HENCHMAN; nHenchman++) + { + oHenchman = GetAssociate(nAssociateType, oPC, nHenchman); + if(oHenchman != OBJECT_INVALID) + { + for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++) + { + oHenchmanAssociate = GetAssociate(nHenchAssociate, oHenchman, 1); + if(oHenchmanAssociate != OBJECT_INVALID) + { + AssignCommand(oHenchmanAssociate, ai_JumpAssociateToPC(oPC)); + } + } + AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC)); + } + } + } + else + { + oHenchman = GetAssociate(nAssociateType, oPC, 1); + if(oHenchman != OBJECT_INVALID) AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC)); + } + } +} +void ai_GhostMode(object oPC, object oAssociate, int nToken, string sAssociateType) +{ + string sText; + if(ai_GetAIMode(oAssociate, AI_MODE_GHOST)) + { + ai_SetAIMode(oAssociate, AI_MODE_GHOST, FALSE); + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + sText = " Turn On clipping through creatures for " + GetName(oAssociate); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ghost_mode_tooltip", sText); + ai_SendMessages(GetName(oAssociate) + " is not in Ghost Mode and will run into creatures.", AI_COLOR_YELLOW, oPC); + } + else + { + ai_SetAIMode(oAssociate, AI_MODE_GHOST, TRUE); + effect eGhost = EffectCutsceneGhost(); + eGhost = UnyieldingEffect(eGhost); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oAssociate); + sText = " Turn Off clipping through creatures for " + GetName(oAssociate); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ghost_mode_tooltip", sText); + ai_SendMessages(GetName(oAssociate) + " is now in Ghost Mode and will clip through creatures.", AI_COLOR_YELLOW, oPC); + } +} +void ai_ChangeCameraView(object oPC, object oAssociate) +{ + object oCamAssociate = GetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE"); + if(oCamAssociate == oAssociate) + { + DeleteLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE"); + AttachCamera(oPC, oPC); + } + else + { + SetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE", oAssociate); + AttachCamera(oPC, oAssociate); + } +} +void ai_SelectCameraView(object oPC) +{ + SetLocalString(oPC, AI_TARGET_MODE, "DM_SELECT_CAMERA_VIEW"); + ai_SendMessages(GetName(oPC) + " select an object to change the camera view to.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE); +} +void ai_OpenInventory(object oAssociate, object oPC) +{ + // Funny things happen when you open associate inventories when they are not + // within sight. + if(LineOfSightObject(oPC, oAssociate)) + { + OpenInventory(oAssociate, oPC); + } + else ai_SendMessages(GetName(oAssociate) + " is not within sight!", AI_COLOR_RED, oPC); +} +void ai_SelectOpenInventory(object oPC) +{ + SetLocalString(oPC, AI_TARGET_MODE, "DM_SELECT_OPEN_INVENTORY"); + ai_SendMessages(GetName(oPC) + " select an object to open its inventory.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); +} +void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0) +{ + int nIndex = StringToInt(GetStringRight(sElem, 1)); + json jPlugins, jPlugin; + if(bUser == 1) // From DM command menu. + { + string sName = ai_RemoveIllegalCharacters(GetName(oPC)); + jPlugins = ai_GetCampaignDbJson("plugins", sName, AI_DM_TABLE); + } + else if(bUser == 2) // From DM plugin menu, master plugin list. + { + jPlugins = ai_GetCampaignDbJson("plugins"); + } + else jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + jPlugin = JsonArrayGet(jPlugins, nIndex); + string sScript = JsonGetString(JsonArrayGet(jPlugin, 0)); + if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "") + { + ai_SendMessages(sScript + " not found by ResMan!", AI_COLOR_RED, oPC); + } + else + { + string sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + ai_SendMessages("Executing plugin " + sName + ".", AI_COLOR_GREEN, oPC); + ExecuteScript(sScript, oPC); + } +} diff --git a/src/module/nss/0i_color.nss b/src/module/nss/0i_color.nss new file mode 100644 index 0000000..b18fe7a --- /dev/null +++ b/src/module/nss/0i_color.nss @@ -0,0 +1,70 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_color +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts that are used to change the color of names and text. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Basic color codes. Message Notes +const string AI_COLOR_BLACK = "000"; // Nothing. +const string AI_COLOR_WHITE = "999"; // _Debug messages. +const string AI_COLOR_GRAY = "666"; // Server messages +const string AI_COLOR_YELLOW = "990"; // Generic messages to players. +const string AI_COLOR_DARK_YELLOW = "660"; // +const string AI_COLOR_RED = "900"; // Negative message to players. +const string AI_COLOR_DARK_RED = "600"; // +const string AI_COLOR_GREEN = "080"; // Positive message to players. +const string AI_COLOR_DARK_GREEN = "060"; // +const string AI_COLOR_BLUE = "009"; // +const string AI_COLOR_DARK_BLUE = "006"; // In game descriptive text. +const string AI_COLOR_CYAN = "099"; // +const string AI_COLOR_DARK_CYAN = "066"; // +const string AI_COLOR_MAGENTA = "909"; // +const string AI_COLOR_DARK_MAGENTA = "606";// +const string AI_COLOR_LIGHT_MAGENTA = "868"; // <âcâ> Combat text: Enemy name color. +const string AI_COLOR_ORANGE = "950"; // +const string AI_COLOR_DARK_ORANGE = "940"; // Combat text: base text color. +const string AI_COLOR_GOLD = "860"; // +// Strips the color codes from sText +string ai_StripColorCodes(string sText); +// This function will make sString be the specified color +// as specified in sRGB. RGB is the Red, Green, and Blue +// Each color can have a value from 0 to 9. +// 1 - 0(20)[ ] 142 - 5(8E)[?] +// 32 - 1(20)[ ] 170 - 6(AA)[ª] +// 57 - 2(39)[9] 198 - 7(C6)[Æ] +// 85 - 3(55)[U] 226 - 8(E2)[â] +// 113 - 4(71)[q] 255 - 9(FE)[ÿ] +string ai_AddColorToText(string sText, string sRGB = AI_COLOR_WHITE); + +string ai_StripColorCodes(string sText) +{ + string sColorCode, sChar; + int nStringLength = GetStringLength(sText); + int i = FindSubString(sText, "" + // End the color token + sText + ""; +} diff --git a/src/module/nss/0i_combat.nss b/src/module/nss/0i_combat.nss new file mode 100644 index 0000000..6c40eb1 --- /dev/null +++ b/src/module/nss/0i_combat.nss @@ -0,0 +1,3498 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_combat +//////////////////////////////////////////////////////////////////////////////// + Include scripts for combat scripts. +*/////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// +#include "0i_messages" +#include "0i_items" +#include "0i_spells" +// This structure is used to represent the number and type of +// enemies that a creature is facing, divided into four main +// categories: FIGHTERS, CLERICS, MAGES, MONSTERS. +struct stClasses +{ + int FIGHTERS; + int FIGHTER_LEVELS; + int CLERICS; + int CLERIC_LEVELS; + int MAGES; + int MAGE_LEVELS; + int MONSTERS; + int MONSTER_LEVELS; + int TOTAL; + int TOTAL_LEVELS; +}; +struct stTarget +{ + object oTarget; + int nValue; + int nBestValue; + int nBestSecondaryValue; + float fNearestRange; + float fNearestSecondaryRange; + int nIndex; + int nSecondaryIndex; + string sTargetType; +}; +//****************************************************************************** +//************ GET TARGETS USING THE OBJECT SEARCH FUNCTIONS ******************* +//****************************************************************************** +// Returns the nearest enemy that is not disabled from oCreature. +// You may pass in any of the CREATURE_TYPE_* constants +// used in GetNearestCreature as nCType1 & nCType2, with +// corresponding values for nCValue1 & nCValue2. +// NOTE: CREATURE_TYPE_PERCEPTION = 7, PERCEPTION_SEEN = 7. +// bDisabled = TRUE will also return any disabled targets that are not dead. +object ai_GetNearestEnemy(object oCreature, int nNth = 1, int nCType1 = -1, int nCValue1 = -1, int nCType2 = -1, int nCValue2 = -1, int bDisabled = FALSE); +// Returns the nearest ally from oCreature. +// You may pass in any of the CREATURE_TYPE_* constants +// used in GetNearestCreature as nCType1 & nCType2, with +// corresponding values for nCValue1 & nCValue2. +// NOTE: CREATURE_TYPE_PERCEPTION = 7, PERCEPTION_SEEN = 7. +object ai_GetNearestAlly(object oCreature, int nNth = 1, int nCType1 = -1, int nCValue1 = -1, int nCType2 = -1, int nCValue2 = -1); +// Returns the number of alive enemies grouped near oCreature within fDistance. +int ai_GetNumOfEnemiesInGroup(object oCreature, float fDistance = AI_RANGE_MELEE); +// Returns the number of alive allies grouped near oCreature within fDistance. +int ai_GetNumOfAlliesInGroup(object oCreature, float fDistance = AI_RANGE_MELEE); +// Returns the number of creatures of nRacial_Type within fDistance that can be seen by oCreature. +int ai_GetRacialTypeCount(object oCreature, int nRacial_Type, float fDistance = AI_RANGE_PERCEPTION); +// Returns the weakest attacker that is in melee or is attacking oCreature's master. +object ai_GetLowestCRAttackerOnMaster(object oCreature); + +//****************************************************************************** +//******************** SET/CLEAR COMBAT STATE FUNCTIONS ************************ +//****************************************************************************** +// Sets oCreatures's combat state by setting variables for AI_ALLIES and AI_ENEMIES. +// Returns the nearest visible enemy. +object ai_SetCombatState(object oCreature); +// Clears all variables that were define for the current round for oCreature. +void ai_ClearCombatState(object oCreature); + +//****************************************************************************** +//*************** GET TARGETS USING COMBAT STATE FUNCTIONS ********************* +//****************************************************************************** +// These functions will find a target or an index to a target based on the +// combat state variables created by the function ai_SetCombatState. + +// Returns the Index of the nearest creature seen within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetNearestIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest creature seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetNearestTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest creature seen with the lowest combat rating +// within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetLowestCRIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest creature seen with the lowest combat rating within fMaxRange +// in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetLowestCRTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest creature seen with the highest combat rating +// within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetHighestCRIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest creature seen with the highest combat rating within fMaxRange +// in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetHighestCRTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the creature seen with the lowest enemies to oCreature that +// they are in melee with minus the number of allies to the caller they are in +// melee with within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetLowestMeleeIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY); +// Returns the index of the creature seen with the most enemies to the caller that +// they are in melee with minus the number of allies to oCreature they are in +// melee with within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetHighestMeleeIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY); +// Returns a creature of sTargetType where they have the least number of +// allies and the most number of enemies within fMaxRange in the combat state. +// Returns OBJECT_INVALID if there is not a good creature to select. +// sTargetType is either AI_ENEMY, or AI_ALLY. +object ai_GetGroupedTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY); +// Returns the index of the nearest creature with the least % of hitpoints within +// fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetMostWoundedIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the creature with the lowest health seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetMostWoundedTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest ally with the least % of hitpoints within +// fMaxRange in the combat state. +// This also filters for AI_MODE_PARTY_HEALING_OFF and AI_MODE_SELF_HEALING_OFF. +// If no ally is found then it will return an index of 0. +int ai_GetAllyToHealIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the ally with the lowest health seen within fMaxRange in the combat state. +// This also filters for AI_MODE_PARTY_HEALING_OFF and AI_MODE_SELF_HEALING_OFF. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetAllyToHealTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the creature with the lowest fortitude save seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetLowestFortitudeSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the creature with the lowest reflex save seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetLowestReflexSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the creature with the lowest will save seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetLowestWillSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the creature with the lowest save based on nSpell save type seen +// within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +object ai_GetSpellTargetBasedOnSaves(object oCreature, int nSpell, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the index of the nearest creature seen that is busy attacking an ally +// within fMaxRange in the combat state. +// If none is found then it will return 0. +int ai_GetSneakAttackIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE); +// Returns the index of the nearest creature seen that is busy attacking an ally +// within fMaxRange in the combat state. +// If none is found then it will return 0. +int ai_GetNearestIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest combat creature seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetNearestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest creature seen with the lowest combat rating +// that is not in a dangerous area of effect within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetLowestCRIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the lowest combat creature seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetLowestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest creature seen with the highest combat rating +// that is not in a dangerous area of effect within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetHighestCRIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the highest combat creature seen within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +object ai_GetHighestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the creature seen with the most enemies to oCreature that +// they are in melee with minus the number of allies to oCreature they are in +// melee with that is not in a dangerous area of effect within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_GetHighestMeleeIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY); +// Returns a creature of sTargetType where they have the least number of +// allies and the most number of enemies within fMaxRange that are not in a +// dangerous area of effect in the combat state. +// Returns OBJECT_INVALID if there is not a good creature to select. +// sTargetType is either AI_ENEMY, or AI_ALLY. +object ai_GetGroupedTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY); +// Returns the nearest creature seen of nClassType within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetNearestClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the creature with the lowest combat rating seen of nClassType within +// fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetLowestCRClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the creature with the highest combat rating seen of nClassType within +// fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetHighestCRClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest creature seen of nRacialType within fMaxRange in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetNearestRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the creature with the lowest combat rating seen of nRacialType within +// fMaxRange in the combat state. Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetLowestCRRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the creature with the highest combat rating seen of nRacialType within +// fMaxRange in the combat state. Returns OBJECT_INVALID if no creature is found. +// sTargetType is either AI_ENEMY or AI_ALLY. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetHighestCRRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the nearest enemy seen that is attacking an ally with the least +// number of enemies on them within fMaxRange in the combat state. +// If none is found then it will return 0. +object ai_GetFlankTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE); +// Returns the nearest enemy creature seen wihtin fMaxRange that is a favored enemy +// of the caller in the combat state. +// Returns OBJECT_INVALID if no creature is found. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetNearestFavoredEnemyTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE); +// Returns the best target for melee combat based if we are in melee or not. +// If not in melee it will get the nearest target that is not in a dangerous +// area of effect for us to attack in the combat state. +// If in melee it will get the weakest target. +// If it returns OBJECT_INVALID then we should stop the attack. The only way +// to not get a target is if we have been told not to attack strong opponents. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetBestCRTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Returns the nearest target for melee combat based if we are in melee or not. +// If not in melee it will get the nearest target that is not in a dangerous +// area of effect for us to attack in the combat state. +// If it returns OBJECT_INVALID then we should stop the attack. The only way +// to not get a target is if we have been told not to attack strong opponents. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetNearestTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Returns the target with the lowest combat rating for melee combat based if +// we are in melee or not. If not in melee it will get the nearest target that +// is not in a dangerous area of effect for us to attack in the combat state. +// If it returns OBJECT_INVALID then we should stop the attack. The only way +// to not get a target is if we have been told not to attack strong opponents. +// bAlwaysAtk TRUE we attack everything! FALSE we don't attack strong enemies. +object ai_GetLowestCRTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Returns the target with the highest combat rating for melee combat based if +// we are in melee or not. If not in melee it will get the nearest target that +// is not in a dangerous area of effect for us to attack in the combat state. +// If it returns OBJECT_INVALID then we should stop the attack. +object ai_GetHighestCRTargetForMeleeCombat(object oCreature, int nInMelee); +// Returns the Index of the nearest creature seen within fMaxRange in the combat state. +// If no creature is found then it will return an index of 0. +// sTargetType is either AI_ENEMY or AI_ALLY. +int ai_MonsterGetNearestIndex(object oMonster, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE); +// Returns the index of the nearest enemy creature that can see oCreature. +int ai_GetNearestIndexThatSeesUs(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION); +// Returns the nearest creature attacking the caller within fMaxRange in the combat state. +// Returns OBJECT_INVALID if oCreature is not being attacked. +object ai_GetEnemyAttackingMe(object oCreature, float fMaxRange = AI_RANGE_MELEE); +// Returns the nearest creature attacking oAlly from oCreature within fMaxRange +// in the combat state. +// Returns OBJECT_INVALID if oAlly is not being attacked. +object ai_GetEnemyAttackingMyAlly(object oCreature, object oAlly, float fMaxRange = AI_RANGE_MELEE); +// Returns the number of enemies within fMaxRange of the caller in the combat state. +int ai_GetNumOfEnemiesInRange(object oCreature, float fMaxRange = AI_RANGE_MELEE); +// Returns the best ally target withing fMaxRange for nSpell to be cast on. +// Uses the ai_spells.2da file to pick a target. +object ai_GetAllyBuffTarget(object oCreature, int nSpell, float fMaxRange = AI_RANGE_BATTLEFIELD); + +//****************************************************************************** +//******************** OTHER COMBAT FUNCTIONS ******************************** +//****************************************************************************** + +// Returns the current round that oCreature is in for this combat. +int ai_GetCurrentRound(object oCreature); +// Returns the difficulty of the battle based on the combat state. +// nDifficulty is Enemy level - Ally level + 20 + Player adjustment. +// 20+ : Impossible - Cannot win. +// 17 to 19 : Overpowering - Use all of our powers. +// 15 to 16 : Very Difficult - Use all of our power (Highest level spells). +// 11 to 14 : Challenging - Use most of our power (Higher level powers). +// 8 to 10 : Moderate - Use half of our power (Mid level powers and less). +// 5 to 7 : Easy - Use our weaker powers (Lowest level powers). +// 2 to 4 : Effortless - Don't waste spells and powers on this. +// 1 or less: Pointless - We probably should ignore these dangers. +int ai_GetDifficulty(object oCreature); +// Returns oCreatures Combat rating. +//(BAB + AC - 10) / 2 +int ai_GetMyCombatRating(object oCreature); +// Returns the last creature oCreature attacked. +// bPhysical checks for creatures attacked in melee or range with a weapon. +// bSpell will look for creatures attacked by a spell. +object ai_GetAttackedTarget(object oCreature, int bPhysical = TRUE, int bSpell = FALSE); +// Returns TRUE if oCreature is of nClassType; +// May also check for general Class types with +// AI_CLASS_TYPE_ARCANE, AI_CLASS_TYPE_DIVINE, AI_CLASS_TYPE_CASTER, AI_CLASS_TYPE_WARRIOR. +int ai_CheckClassType(object oCreature, int nClassType); +// Returns TRUE if oCreature is of nRacialType; +// May also check for general racial types with +// AI_RACIAL_TYPE_ANIMAL_BEAST +int ai_CheckRacialType(object oCreature, int nRacialType); +// Saves oCreatures Normal appearance if they are not polymorphed and it has +// not already been saved. +void ai_SetNormalAppearance(object oCreature); +// Returns the normal appearance of oCreature. +int ai_GetNormalAppearance(object oCreature); +// Return the number and levels of all creatures within fMaxRange. +// They are grouped into Fighters, Clerics, Mages, and Monsters. +struct stClasses ai_GetFactionsClasses(object oCreature, int bEnemy = TRUE, float fMaxRange = AI_RANGE_BATTLEFIELD); +// This will return the class with the most levels. +// Returns a string of "FIGHTER", "CLERIC", "MAGE", or "MONSTER". +// Execute with GetFactionsClasses. +string ai_GetMostDangerousClass(struct stClasses stCount); +// Equips the best weapon, ranged or melee. +// Returns TRUE if equiped, FALSE if not. +// oTarget is the creature the caller is targeting. +void ai_EquipBestWeapons(object oCreature, object oTarget = OBJECT_INVALID); +// Equips a melee weapon AND checks for shield, two weapons, two handed, etc. +// Returns TRUE if equiped, FALSE if not. +// oTarget is the creature the caller is targeting. +int ai_EquipBestMeleeWeapon(object oCreature, object oTarget = OBJECT_INVALID); +// Equips a ranged weapon AND checks for ammo. +// Returns TRUE if equiped, FALSE if not. +// oTarget is the creature the caller is targeting. +int ai_EquipBestRangedWeapon(object oCreature, object oTarget = OBJECT_INVALID); +// Equips the best weapon for a monk character. +// Returns TRUE if equiped, FALSE if not. +// oTarget is the creature the caller is targeting. +int ai_EquipBestMonkMeleeWeapon(object oCreature, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature is in a Dangerous Area of Effect in fMaxRange. +// bMove will attempt to move oCreature out of the Dangerous AOE if needed. +int ai_IsInADangerousAOE(object oCreature, float fMaxRange = AI_RANGE_BATTLEFIELD, int bMove = FALSE); +// Returns 1 if oHidden has an Invisiblity effect, Can't be spotted but can be heard. +// Returns 2 if oHidden has a Darkness effect. Can't be spotted but can be heard. +// Returns 3 if oHidden has a Sanctuary effect, Can't be spotted or heard. +// Returns 4 if oHidden is in stealth mode, Can be spotted and heard. +int ai_GetIsHidden(object oHidden); +// Returns TRUE if if oCaster has a good chance of effecting oCreature with nSpell. +int ai_CastOffensiveSpellVsTarget(object oCaster, object oCreature, int nSpell); +// Gets the base DC for a dragon. +int ai_GetDragonDC(object oCreature); +// Set oCreature's ai scripts based on its first class or the variable "AI_DEFAULT_SCRIPT". +void ai_SetCreatureAIScript(object oCreature); +// Returns TRUE if oTarget is immune to sneak attacks. +int ai_IsImmuneToSneakAttacks(object oCreature, object oTarget); +// Returns TRUE if iIndex target has a higher combat rating than oCreature. +int ai_IsStrongerThanMe(object oCreature, int nIndex); +// Returns TRUE if oTarget's CR is within nAdj of oCreature's level, otherwise FALSE. +int ai_StrongOpponent(object oCreature, object oTarget, int nAdj = 2); +// Returns TRUE if attacking oTarget with Power attack is a good option. +int ai_PowerAttackGood(object oCreature, object oTarget, float fAdj); +// Returns TRUE if oTarget's AC - oCreature Atk - nAtkAdj can hit within 25% to 75%. +int ai_AttackPenaltyOk(object oCreature, object oTarget, float fAtkAdj); +// Returns TRUE if oCreature AC - oTarget's Atk is less than 20. +int ai_ACAdjustmentGood(object oCreature, object oTarget, float fACAdj); +// Checks oCreatures melee weapon to see if they can kill oTarget in one hit. +int ai_WillKillInOneHit(object oCreature, object oTarget); +// Returns TRUE if oCreature has Mobility, SpringAttack, or a high Tumble. +int ai_CanIMoveInCombat(object oCreature); +// Returns TRUE if oCreature can safely fire a ranged weapon. +int ai_CanIUseRangedWeapon(object oCreature, int nInMelee); +// Returns TRUE if oCreature moves before the action. FALSE if they do not move. +// and -1 if the action is canceled. +// Checks current combat state to see if oCreature needs to move before using an action. +int ai_CheckCombatPosition(object oCreature, object oTarget, int nInMelee, int nAction, int nBaseItemType = 0); + +//****************************************************************************** +//************ GET TARGETS USING THE OBJECT SEARCH FUNCTIONS ******************* +//****************************************************************************** +object ai_GetNearestEnemy(object oCreature, int nNth = 1, int nCType1 = -1, int nCValue1 = -1, int nCType2 = -1, int nCValue2 = -1, int bDisabled = FALSE) +{ + object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, + oCreature, nNth, nCType1, nCValue1, nCType2, nCValue2); + if(bDisabled) + { + while(oTarget != OBJECT_INVALID && GetIsDead(oTarget)) + { + oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, + oCreature, ++nNth, nCType1, nCValue1, nCType2, nCValue2); + } + } + else + { + while(oTarget != OBJECT_INVALID && ai_Disabled(oTarget)) + { + oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, + oCreature, ++nNth, nCType1, nCValue1, nCType2, nCValue2); + } + } + return oTarget; +} +object ai_GetNearestAlly(object oCreature, int nNth = 1, int nCType1 = -1, int nCValue1 = -1, int nCType2 = -1, int nCValue2 = -1) +{ + return GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, + oCreature, ++nNth, nCType1, nCValue1, nCType2, nCValue2); +} +int ai_GetNumOfEnemiesInGroup(object oCreature, float fDistance = AI_RANGE_MELEE) +{ + int nCnt; + location lLocation = GetLocation(oCreature); + object oEnemy = GetFirstObjectInShape(SHAPE_SPHERE, fDistance, lLocation); + while(oEnemy != OBJECT_INVALID) + { + if(GetIsEnemy(oEnemy, oCreature) && !GetIsDead(oEnemy)) nCnt++; + oEnemy = GetNextObjectInShape(SHAPE_SPHERE, fDistance, lLocation); + } + return nCnt; +} +int ai_GetNumOfAlliesInGroup(object oCreature, float fDistance = AI_RANGE_MELEE) +{ + int nCnt; + location lLocation = GetLocation(oCreature); + object oAlly = GetFirstObjectInShape(SHAPE_SPHERE, fDistance, lLocation); + while(oAlly != OBJECT_INVALID) + { + if(GetReputation(oCreature, oAlly) > 89 && oAlly != oCreature && !GetIsDead(oAlly)) + { + nCnt++; + } + oAlly = GetNextObjectInShape(SHAPE_SPHERE, fDistance, lLocation); + } + return nCnt; +} +int ai_GetRacialTypeCount(object oCreature, int nRacial_Type, float fDistance = AI_RANGE_PERCEPTION) +{ + int nCnt = 1; + int nCount = 0; + object oEnemy = ai_GetNearestEnemy(oCreature, nCnt, + CREATURE_TYPE_PERCEPTION, + PERCEPTION_SEEN, + CREATURE_TYPE_RACIAL_TYPE, + nRacial_Type); + while(oEnemy != OBJECT_INVALID && GetDistanceBetween(oEnemy, oCreature) <= fDistance) + { + if(!ai_GetHasEffectType(oEnemy, EFFECT_TYPE_TURNED)) nCount++; + nCnt++; + oEnemy = ai_GetNearestEnemy(oCreature, nCnt, + CREATURE_TYPE_PERCEPTION, + PERCEPTION_SEEN, + CREATURE_TYPE_RACIAL_TYPE, + nRacial_Type); + } + return nCount; +} +object ai_GetLowestCRAttackerOnMaster(object oCreature) +{ + object oTarget = OBJECT_INVALID, oMaster = GetMaster(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "419", "Checking for weakest attacker on " + GetName(oMaster)); + int nEnemyCombatRating, nWeakestCombatRating, nCntr = 1; + float fNearest = AI_RANGE_MELEE + 1.0f; + // Get the weakest opponent in melee with our master. + object oEnemy = ai_GetNearestEnemy(oMaster, nCntr, 7, 7); + float fDistance = GetDistanceBetween(oMaster, oEnemy); + while (oEnemy != OBJECT_INVALID && fDistance <= AI_RANGE_MELEE) + { + nEnemyCombatRating = ai_GetMyCombatRating(oEnemy); + if(AI_DEBUG) ai_Debug("0i_combat", "428", GetName(oEnemy) + " nECR: " + IntToString(nEnemyCombatRating)); + if (nEnemyCombatRating < nWeakestCombatRating || + nEnemyCombatRating == nWeakestCombatRating && fDistance < fNearest) + { + fNearest = fDistance; + nWeakestCombatRating = nEnemyCombatRating; + oTarget = oEnemy; + } + oEnemy = ai_GetNearestEnemy(oMaster, ++nCntr, 7, 7); + } + // No targets in melee with our master, lets see if there is a ranged attacker. + if (oTarget == OBJECT_INVALID) oTarget = GetLastHostileActor(oMaster); + return oTarget; +} + +//****************************************************************************** +//******************** SET/CLEAR COMBAT STATE FUNCTIONS ************************ +//****************************************************************************** + +object ai_SetCombatState(object oCreature) +{ + if(AI_DEBUG) ai_Counter_Start(); + object oMaster = GetMaster(); + if(oMaster == OBJECT_INVALID) oMaster = oCreature; + int nEnemyNum, nEnemyPower, nAllyNum, nAllyPower, nInMelee, nMagic; + int nHealth, nNth, nAllies, nPower, nDisabled, bThreat,nObjects; + int nEnemyHighestPower, nAllyHighestPower; + float fNearest = AI_RANGE_BATTLEFIELD; + float fDistance; + float fMaxRange = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fMaxRange == 0.0) fMaxRange = AI_RANGE_PERCEPTION; + string sCnt, sDebugText; + location lLocation = GetLocation(oMaster); + object oMelee, oNearestEnemy = OBJECT_INVALID; + if(AI_DEBUG) ai_Debug("0i_combat", "491", "************************************************************"); + if(AI_DEBUG) ai_Debug("0i_combat", "492", "******************* CREATING COMBAT DATA *******************"); + if(AI_DEBUG) ai_Debug("0i_combat", "493", GetName(oCreature)); + // We want to include ourselves in the combat state. + object oObject = GetFirstObjectInShape(SHAPE_SPHERE, AI_RANGE_BATTLEFIELD, lLocation); + // Get all creatures within 40 meters(5 meters beyond our perception of 35). + // Centered on either the creature or their master. + while(oObject != OBJECT_INVALID) + { + // Process all enemies. + if(GetIsEnemy(oObject, oCreature)) + { + if(GetObjectSeen(oObject, oCreature) || GetObjectHeard(oObject, oCreature)) + { + fDistance = GetDistanceBetween(oObject, oCreature); + if(fDistance <= fMaxRange) + { + // ********** Get the Total levels of the Enemy ********** + nPower = ai_GetCharacterLevels(oObject); + if(nPower < 1) nPower = 1; + if(nEnemyHighestPower < nPower) nEnemyHighestPower = nPower; + nEnemyPower += nPower; + // ********** Check if the Enemy is disabled ********** + bThreat = TRUE; + nDisabled = ai_Disabled(oObject); + if(nDisabled) + { + if(AI_DEBUG) sDebugText += "**** DISABLED(" + IntToString(nDisabled) + ") ****"; + // Decide if they are still a threat: 1 - dead, 2 - Bleeding. + if(nDisabled == 1 || nDisabled == 2 || + //nDisabled == EFFECT_TYPE_CONFUSED || + //nDisabled == EFFECT_TYPE_FRIGHTENED || + //nDisabled == EFFECT_TYPE_PARALYZE || + nDisabled == EFFECT_TYPE_CHARMED || + nDisabled == EFFECT_TYPE_PETRIFY) + { + bThreat = FALSE; + if(AI_DEBUG) ai_Debug("0i_combat", "527", "Enemy: " + GetName(oObject) + sDebugText); + } + } + // If they are using the coward ai then treat them as frightened. + // we place it here as an else so we don't overwrite another disabled effect. + else if(GetLocalString(oObject, AI_COMBAT_SCRIPT) == "ai_coward") + { + nDisabled = EFFECT_TYPE_FRIGHTENED; + // !!!! For /DEBUG CODE !!!! + if(AI_DEBUG) sDebugText += "**** DISABLED(" + IntToString(nDisabled) + ") ****"; + } + if(bThreat) + { + sCnt = IntToString(++nEnemyNum); + // ********** Set if the Enemy is disabled ********** + SetLocalInt(oCreature, AI_ENEMY_DISABLED + sCnt, nDisabled); + // ********** Set the Enemy Object ********** + SetLocalObject(oCreature, AI_ENEMY + sCnt, oObject); + // ********** Set the Enemy Combat Rating ********** + SetLocalInt(oCreature, AI_ENEMY_COMBAT + sCnt, ai_GetMyCombatRating(oObject)); + // ********** Set the Enemy Health Percentage ********** + nHealth = ai_GetPercHPLoss(oObject); + SetLocalInt(oCreature, AI_ENEMY_HEALTH + sCnt, nHealth); + // ********** Set the number of enemies near the enemy ********** + nInMelee = 0; + nNth = 1; + oMelee = GetNearestObject(OBJECT_TYPE_CREATURE, oObject, nNth); + while(oMelee != OBJECT_INVALID && !GetIsDead(oMelee) && + GetDistanceBetween(oMelee, oObject) < AI_RANGE_MELEE) + { + // We add an enemy to the group. + if(GetIsEnemy(oMelee, oCreature)) nInMelee++; + oMelee = GetNearestObject(OBJECT_TYPE_CREATURE, oObject, ++nNth); + } + SetLocalInt(oCreature, AI_ENEMY_MELEE + sCnt, nInMelee); + // ********** Set the Enemies distance ********** + fDistance = GetDistanceBetween(oObject, oCreature); + SetLocalFloat(oCreature, AI_ENEMY_RANGE + sCnt, fDistance); + // ********** Set if the Enemy is perceived ********** + if(GetObjectSeen(oObject, oCreature) || + (GetObjectHeard(oObject, oCreature) && fDistance <= AI_RANGE_MELEE && + ai_GetIsHidden(oObject))) + { + SetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCnt, TRUE); + if(AI_DEBUG) sDebugText += "**** PERCEIVED Seen: " + + IntToString(GetObjectSeen(oObject, oCreature)) + + " Heard: " + IntToString(GetObjectHeard(oObject, oCreature)) + " ****"; + } + else SetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCnt, FALSE); + // ********** Set the Nearest Enemy seen ********** + if(fDistance < fNearest) + { + fNearest = fDistance; + oNearestEnemy = oObject; + } + } + } + // !!! Debug code !!! + if(AI_DEBUG && fDistance < AI_RANGE_MELEE) sDebugText += "**** MELEE ****"; + if(AI_DEBUG) ai_Debug("0i_combat", "587", "Enemy(" + IntToString(nEnemyNum) + "): " + + GetName(oObject) + sDebugText); + if(AI_DEBUG) ai_Debug("0i_combat", "589", "nHealth: " + IntToString(nHealth) + + " nInMelee: " + IntToString(nInMelee) + + " fDistance: " + FloatToString(fDistance, 0, 2) + + " nNum: " + IntToString(nEnemyNum) + + " nPower: " + IntToString(nEnemyPower / 2)); + } + else + { + // ********** Also add the levels of Unknown Enemies *********** + nPower = FloatToInt(ai_GetCharacterLevels(oObject) / 1.5); + if(nPower < 1) nPower = 1; + nEnemyPower += nPower; + if(AI_DEBUG) ai_Debug("0i_combat", "601", "Enemy(NOT PERCEIVED): " + + GetName(oObject) + " fDistance: " + + FloatToString(GetDistanceBetween(oObject, oCreature), 0, 2) + + " nPower: " + IntToString(nEnemyPower)); + } + } + // Process all Allies. + else if(GetFactionEqual(oObject, oCreature)) + { + // ********** Set if the Ally is disabled ********** + nDisabled = ai_Disabled(oObject); + if(nDisabled) + { + sDebugText += "**** DISABLED(" + IntToString(nDisabled) + ") ****"; + SetLocalInt(oCreature, AI_ALLY_DISABLED + sCnt, nDisabled); + } + if(nDisabled != 1) + { + sCnt = IntToString(++nAllyNum); + // ********** Set the Ally Object ********** + SetLocalObject(oCreature, AI_ALLY + sCnt, oObject); + // ********** Set the Ally Combat Rating ********** + SetLocalInt(oCreature, AI_ALLY_COMBAT + sCnt, ai_GetMyCombatRating(oObject)); + // ********** Set the Ally Health Percentage ********** + nHealth = ai_GetPercHPLoss(oObject); + SetLocalInt(oCreature, AI_ALLY_HEALTH + sCnt, nHealth); + // ********** Set the number of enemies near the ally ********** + nInMelee = 0; + nNth = 1; + oMelee = GetNearestObject(OBJECT_TYPE_CREATURE, oObject, nNth); + while(oMelee != OBJECT_INVALID && !GetIsDead(oMelee) && + GetDistanceBetween(oMelee, oObject) < AI_RANGE_MELEE) + { + if(GetIsEnemy(oMelee, oCreature)) nInMelee++; + //else nInMelee--; + oMelee = GetNearestObject(OBJECT_TYPE_CREATURE, oObject, ++nNth); + } + SetLocalInt(oCreature, AI_ALLY_MELEE + sCnt, nInMelee); + // ********** Set the Allies distance ********** + SetLocalFloat(oCreature, AI_ALLY_RANGE + sCnt, GetDistanceBetween(oObject, oCreature)); + // ********** All allies are considered to be seen ********** + SetLocalInt(oCreature, AI_ALLY_PERCEIVED + sCnt, TRUE); + // ********** Get the Total levels of the Allies ********** + nPower = ai_GetCharacterLevels(oObject); + if(nAllyHighestPower < nPower) nAllyHighestPower = nPower; + nAllyPower +=(nPower * nHealth) / 100; + if(AI_DEBUG) ai_Debug("0i_combat", "647", "Ally(" + IntToString(nAllyNum) + "): " + + GetName(oObject) + sDebugText); + if(AI_DEBUG) ai_Debug("0i_combat", "649", "nHealth: " + IntToString(nHealth) + + " nInMelee: " + IntToString(nInMelee) + + " fDistance: " + FloatToString(GetDistanceToObject(oObject), 0, 2) + + " nNum: " + IntToString(nAllyNum) + + " nPower: " + IntToString(nAllyPower / 2)); + } + } + if(AI_DEBUG) sDebugText = ""; + oObject = GetNextObjectInShape(SHAPE_SPHERE, AI_RANGE_BATTLEFIELD, lLocation); + } + if(AI_DEBUG) ai_Debug("0i_combat", "659", "Nearest Enemy: " + GetName(oNearestEnemy)); + if(AI_DEBUG) ai_Debug("0i_combat", "660", "****************** FINISHED COMBAT DATA *******************"); + if(AI_DEBUG) ai_Debug("0i_combat", "661", "************************************************************"); + // Lets save processing by only clearing previous enemy data we don't overwrite. + int nPreviousEnd = GetLocalInt(oCreature, AI_ENEMY_NUMBERS); + int nCnt = nEnemyNum + 1; + if(AI_DEBUG) ai_Debug("0i_combat", "665", "Clearing Enemy Combat Data: nPreviousEnd: " + + IntToString(nPreviousEnd) + " nCurrentEnd: " + IntToString(nCnt - 1)); + while(nPreviousEnd >= nCnt) + { + sCnt = IntToString(nCnt); + if(AI_DEBUG) ai_Debug("0i_combat", "670", "Clearing Enemy Combat Data: " + sCnt + " " + + GetName(GetLocalObject(oCreature, AI_ENEMY + sCnt))); + DeleteLocalObject(oCreature, AI_ENEMY + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCnt); + DeleteLocalFloat(oCreature, AI_ENEMY_RANGE + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_COMBAT + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_MELEE + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_HEALTH + sCnt); + nCnt ++; + } + // Lets save processing by only clearing previous ally data we don't overwrite. + nPreviousEnd = GetLocalInt(oCreature, AI_ALLY_NUMBERS); + nCnt = nAllyNum + 1; + if(AI_DEBUG) ai_Debug("0i_combat", "683", "Clearing Ally Combat Data: nPreviousEnd: " + + IntToString(nPreviousEnd) + " nCurrentEnd: " + IntToString(nCnt - 1)); + while(nPreviousEnd >= nCnt) + { + sCnt = IntToString(nCnt); + if(AI_DEBUG) ai_Debug("0i_combat", "688", "Clearing Ally Combat Data: " + sCnt + " " + + GetName(GetLocalObject(oCreature, AI_ENEMY + sCnt))); + DeleteLocalObject(oCreature, AI_ALLY + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_PERCEIVED + sCnt); + DeleteLocalFloat(oCreature, AI_ALLY_RANGE + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_COMBAT + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_MELEE + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_HEALTH + sCnt); + nCnt ++; + } + // Finally set all group states. + SetLocalInt(oCreature, AI_ENEMY_NUMBERS, nEnemyNum); + // Total enemy power is half the levels of all enemies + the total levels + // of the highest level enemy. + nEnemyPower = (nEnemyPower / 2) + nEnemyHighestPower; + SetLocalInt(oCreature, AI_ENEMY_POWER, nEnemyPower); + SetLocalObject(oCreature, AI_ENEMY_NEAREST, oNearestEnemy); + SetLocalInt(oCreature, AI_ALLY_NUMBERS, nAllyNum); + // Total ally power is half the levels of all allies + the total levels + // of the highest level ally, only used by associates. + nAllyPower = (nAllyPower / 2) + nAllyHighestPower; + SetLocalInt(oCreature, AI_ALLY_POWER, nAllyPower); + if(AI_DEBUG) ai_Debug("0i_combat", "710", "nEnemyPower: " + IntToString(nEnemyPower) + + " nEnemyHighestPower: " + IntToString(nEnemyHighestPower) + + " nAllyPower: " + IntToString(nAllyPower) + + " nAllyHighestPower: " + IntToString(nAllyHighestPower)); + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + " has finished the Combat State"); + return oNearestEnemy; +} +void ai_ClearCombatState(object oCreature) +{ + int bEnemyDone, bAllyDone, nCnt = 1; + int nEnemyNum = GetLocalInt(oCreature, AI_ENEMY_NUMBERS); + int nAllyNum = GetLocalInt(oCreature, AI_ALLY_NUMBERS); + if(AI_DEBUG) ai_Debug("0i_combat", "722", "Clearing " + GetName(oCreature) + "'s combat state." + + " nEnemyNum: " + IntToString(nEnemyNum) + " nAllyNum: " + IntToString(nAllyNum)); + string sCnt; + while(!bEnemyDone || !bAllyDone) + { + sCnt = IntToString(nCnt); + if(nCnt <= nEnemyNum) + { + if(AI_DEBUG) ai_Debug("0i_combat", "730", "Clearing " + GetName(GetLocalObject(oCreature, AI_ENEMY + sCnt)) + "."); + DeleteLocalObject(oCreature, AI_ENEMY + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_DISABLED + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCnt); + DeleteLocalFloat(oCreature, AI_ENEMY_RANGE + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_COMBAT + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_MELEE + sCnt); + DeleteLocalInt(oCreature, AI_ENEMY_HEALTH + sCnt); + } + else bEnemyDone = TRUE; + if(nCnt <= nAllyNum) + { + if(AI_DEBUG) ai_Debug("0i_combat", "742", "Clearing " + GetName(GetLocalObject(oCreature, AI_ALLY + sCnt)) + "."); + DeleteLocalObject(oCreature, AI_ALLY + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_DISABLED + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_PERCEIVED + sCnt); + DeleteLocalFloat(oCreature, AI_ALLY_RANGE + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_COMBAT + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_MELEE + sCnt); + DeleteLocalInt(oCreature, AI_ALLY_HEALTH + sCnt); + } + else bAllyDone = TRUE; + nCnt++; + } + DeleteLocalObject(oCreature, AI_ENEMY_NEAREST); + DeleteLocalInt(oCreature, AI_ENEMY_NUMBERS); + DeleteLocalInt(oCreature, AI_ENEMY_POWER); + DeleteLocalInt(oCreature, AI_ALLY_NUMBERS); + DeleteLocalObject(oCreature, AI_ALLY_POWER); + // Also clear these combat variables at the end of combat. + DeleteLocalObject(oCreature, AI_ATTACKED_PHYSICAL); + DeleteLocalObject(oCreature, AI_ATTACKED_SPELL); + // Remove Talent variables. + DeleteLocalJson(oCreature, AI_TALENT_CURE); + DeleteLocalJson(oCreature, AI_TALENT_HEALING); + DeleteLocalJson(oCreature, AI_TALENT_ENHANCEMENT); + DeleteLocalJson(oCreature, AI_TALENT_PROTECTION); + DeleteLocalJson(oCreature, AI_TALENT_SUMMON); + DeleteLocalJson(oCreature, AI_TALENT_DISCRIMINANT_AOE); + DeleteLocalJson(oCreature, AI_TALENT_INDISCRIMINANT_AOE); + DeleteLocalJson(oCreature, AI_TALENT_RANGED); + DeleteLocalJson(oCreature, AI_TALENT_TOUCH); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_HEALING); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_ENHANCEMENT); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_PROTECTION); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_SUMMON); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_DISCRIMINANT_AOE); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_INDISCRIMINANT_AOE); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_RANGED); + DeleteLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_TOUCH); + DeleteLocalInt(oCreature, AI_AM_I_SEARCHING); + DeleteLocalInt(oCreature, AI_TRIED_TO_HIDE); + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); + DeleteLocalInt(oCreature, sLastActionVarname); + DeleteLocalInt(oCreature, AI_TALENTS_SET); + DeleteLocalInt(oCreature, AI_ROUND); + DeleteLocalInt(oCreature, sIPHasHasteVarname); + DeleteLocalInt(oCreature, sIPImmuneVarname); + DeleteLocalInt(oCreature, sIPResistVarname); + DeleteLocalInt(oCreature, sIPReducedVarname); + ai_EndCombatRound(oCreature); +} +//****************************************************************************** +//*********************** GET TARGETS INTERNAL FUNCTIONS *********************** +//****************************************************************************** +// These functions are used by the Get Index/ Get Target functions below. + +int ai_TargetIsInRangeofCreature(object oCreature, string sTargetType, string sCounter, float fMaxRange) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "796", "fMaxRange: " + FloatToString(fMaxRange, 0, 2) + + " fTargetRange: " + FloatToString(GetLocalFloat(oCreature, sTargetType + "_RANGE" + sCounter), 0, 2)); + return fMaxRange >= GetLocalFloat(oCreature, sTargetType + "_RANGE" + sCounter); +} +int ai_TargetIsInRangeofMaster(object oCreature, object oTarget) +{ + object oMaster = GetMaster(); + if(oMaster == OBJECT_INVALID) return TRUE; + float fMaxRange = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fMaxRange == 0.0) fMaxRange = 20.0; + float fTargetRangefromMaster = GetDistanceBetween(oTarget, oMaster); + if(AI_DEBUG) ai_Debug("0i_combat", "807", "fMaxRangefromMaster: " + FloatToString(fMaxRange, 0, 2) + + " fTargetRangefromMaster: " + FloatToString(fTargetRangefromMaster, 0, 2)); + return fMaxRange >= fTargetRangefromMaster; +} +struct stTarget ai_CheckForNearestTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "817", "Getting nearest index: " + sIndex + + " fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2) + + " fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2)); + // Lets put any disabled targets and associates if set in a secondary group. + if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) || + (ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget))) + { + if(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange) + { + sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nSecondaryIndex = nIndex; + } + } + else if(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange) + { + sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nIndex = nIndex; + } + return sTarget; +} +struct stTarget ai_CheckForLowestValueTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "835", "Getting lowest value index: " + sIndex + + " fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2) + + " sTarget.nValue: " + IntToString(sTarget.nValue) + + " sTarget.nBestValue: " + IntToString(sTarget.nBestValue) + + " sTarget.nBestSecondaryValue: " + IntToString(sTarget.nBestSecondaryValue)); + // Lets put any disabled targets and associates if set in a secondary group. + if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) || + (ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget))) + { + if(sTarget.nValue < sTarget.nBestSecondaryValue || + (sTarget.nValue == sTarget.nBestSecondaryValue && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange)) + { + sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nBestSecondaryValue = sTarget.nValue; + sTarget.nSecondaryIndex = nIndex; + } + } + // Has less value or equal value and is closer. + else if(sTarget.nValue < sTarget.nBestValue || + (sTarget.nBestValue == sTarget.nValue && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange)) + { + sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nBestValue = sTarget.nValue; + sTarget.nIndex = nIndex; + } + return sTarget; +} +struct stTarget ai_CheckForHighestValueTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "865", "Getting highest value index: " + sIndex + + " fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2) + + " fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2) + + " sTarget.nValue: " + IntToString(sTarget.nValue) + + " sTarget.nBestValue: " + IntToString(sTarget.nBestValue) + + " sTarget.nBestSecondaryValue: " + IntToString(sTarget.nBestSecondaryValue)); + // Lets put any disabled targets and associates if set in a secondary group. + if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) || + (ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget))) + { + if(sTarget.nValue > sTarget.nBestSecondaryValue || + (sTarget.nValue == sTarget.nBestSecondaryValue && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange)) + { + sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nBestSecondaryValue = sTarget.nValue; + sTarget.nSecondaryIndex = nIndex; + } + } + // Has less value or equal value and is closer. + else if(sTarget.nValue > sTarget.nBestValue || + (sTarget.nBestValue == sTarget.nValue && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange)) + { + sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nBestValue = sTarget.nValue; + sTarget.nIndex = nIndex; + } + return sTarget; +} +struct stTarget ai_CheckForNearestAllTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "895", "Getting nearest (not disabled) index: " + sIndex + + " fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2)); + // If we are ignoring associates set then ignore them. + // Has lower value or equal value and is closer. Familiars/Companions/Summons/Dominated. + if(AI_DEBUG) ai_Debug("0i_combat", "911", "Don't Ignore Associate: " + IntToString(!ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES)) + + " Not an Associate? " + IntToString(GetAssociateType(sTarget.oTarget) < 2)); + if((!ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) || GetAssociateType(sTarget.oTarget) < 2) && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange) + { + sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nIndex = nIndex; + } + return sTarget; +} +struct stTarget ai_CheckForLowestValueAllTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "923", "Getting lowest value index: " + sIndex + + " fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) + + " fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2) + + " sTarget.nValue: " + IntToString(sTarget.nValue) + + " sTarget.nBestValue: " + IntToString(sTarget.nBestValue)); + // Has less value or equal value and is closer. Ignoring only Familiars/Companions/Summons/Dominated. + if(AI_DEBUG) ai_Debug("0i_combat", "922", "Don't Ignore Associate: " + IntToString(!ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES)) + + " Not an Associate? " + IntToString(GetAssociateType(sTarget.oTarget) < 2)); + if((!ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) || GetAssociateType(sTarget.oTarget) < 2) && + sTarget.nValue < sTarget.nBestValue || + (sTarget.nBestValue == sTarget.nValue && + GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange)) + { + sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex); + sTarget.nBestValue = sTarget.nValue; + sTarget.nIndex = nIndex; + } + return sTarget; +} + +//****************************************************************************** +//************ GET INDEX/TARGETs USING COMBAT STATE FUNCTIONS ****************** +//****************************************************************************** +// These functions will find a target based on the combat state variables created +// by the function ai_SetCombatState for associates. + +int ai_GetNearestIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(GetLocalInt(oCreature, AI_RULE_AI_DIFFICULTY)) + { + return ai_GetLowestCRIndex(oCreature, fMaxRange, sTargetType, bAlwaysAtk); + } + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "911", "Getting the nearest index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "918", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "931", "Found nearest [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetNearestTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "936", "Getting the nearest target."); + string sIndex = IntToString(ai_GetNearestIndex(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetLowestCRIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 100; + sTarget.nBestSecondaryValue = 100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "953", "Getting the lowest CR index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "960", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "974", "Found lowest CR [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetLowestCRTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "979", "Getting the lowest CR target."); + string sIndex = IntToString(ai_GetLowestCRIndex(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetHighestCRIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "995", "Getting the highest CR index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1002", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1016", "Found highest CR [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetHighestCRTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1021", "Getting the highest CR target."); + string sIndex = IntToString(ai_GetHighestCRIndex(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetLowestMeleeIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 100; + sTarget.nBestSecondaryValue = 100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1037", "Getting the lowest InMelee index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_MELEE" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1058", "Found lowest InMelee [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +int ai_GetHighestMeleeIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1073", "Getting the highest InMelee index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_MELEE" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1094", "Found highest InMelee [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_CheckForGroupedTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1124", "Getting the highest InMelee target."); + string sIndex = IntToString(ai_GetHighestMeleeIndex(oCreature, fMaxRange, sTargetType)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetMostWoundedIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 200; + sTarget.nBestSecondaryValue = 200; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1113", "Getting the most wounded index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1120", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_HEALTH" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1130", "Found most wounded [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetMostWoundedTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1139", "Getting the most wounded target."); + string sIndex = IntToString(ai_GetMostWoundedIndex(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetAllyToHealIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.nBestValue = 200; + sTarget.sTargetType = AI_ALLY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTarget.sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1154", "Getting the most wounded ally to heal index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ALLY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ALLY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ALLY, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, AI_ALLY_HEALTH + sCounter); + sTarget = ai_CheckForLowestValueAllTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ALLY + sCounter); + } + // If we do not have a normal target then we are done.. + if(AI_DEBUG) ai_Debug("0i_combat", "1187", "Found most wounded ally to heal Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetAllyToHealTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1192", "Getting the most wounded ally to heal target."); + string sIndex = IntToString(ai_GetAllyToHealIndex(oCreature, fMaxRange)); + return GetLocalObject(oCreature, AI_ALLY + sIndex); +} +object ai_GetLowestFortitudeSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 200; + sTarget.nBestSecondaryValue = 200; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1113", "Getting the lowest fortitude save index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetFortitudeSavingThrow(sTarget.oTarget); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1232", "Found lowest fortitude save Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, AI_ENEMY + IntToString(sTarget.nIndex)); +} +object ai_GetLowestReflexSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 200; + sTarget.nBestSecondaryValue = 200; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1248", "Getting the lowest reflex save index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetReflexSavingThrow(sTarget.oTarget); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1269", "Found lowest reflex save Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, AI_ENEMY + IntToString(sTarget.nIndex)); +} +object ai_GetLowestWillSaveTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 200; + sTarget.nBestSecondaryValue = 200; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1285", "Getting the lowest will save index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetWillSavingThrow(sTarget.oTarget); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1306", "Found lowest will save Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, AI_ENEMY + IntToString(sTarget.nIndex)); +} +object ai_GetSpellTargetBasedOnSaves(object oCreature, int nSpell, float fMaxRange = AI_RANGE_PERCEPTION) +{ + // Check the spells save type in "ai_spells.2da" and find the weakest + // creature based on that save. + string sSaveType = Get2DAString("ai_spells", "SaveType", nSpell); + if(sSaveType == "Reflex") return ai_GetLowestReflexSaveTarget(oCreature, fMaxRange); + if(sSaveType == "Fortitude") return ai_GetLowestFortitudeSaveTarget(oCreature, fMaxRange); + if(sSaveType == "Will") return ai_GetLowestWillSaveTarget(oCreature, fMaxRange); + // If there is no save then lets see if we can find an enemy with the lowest health. + return ai_GetMostWoundedTarget(oCreature, fMaxRange); +} +int ai_GetNearestIndexThatSeesUs(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1334", "Getting the nearest creature that sees us index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1373", GetName(sTarget.oTarget) + " can see us? " + + IntToString(GetObjectSeen(oCreature, sTarget.oTarget))); + if(GetObjectSeen(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestAllTarget(oCreature, sTarget, nCounter, sCounter); + } + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(AI_DEBUG) ai_Debug("0i_combat", "1354", "Found nearest creature that sees us Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +int ai_GetBestSneakAttackIndex(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + object oAttacking; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1372", "Getting the best sneak attack index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget) && + !ai_IsImmuneToSneakAttacks(oCreature, sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + oAttacking = ai_GetAttackedTarget(sTarget.oTarget); + if(AI_DEBUG) ai_Debug("0i_combat", "1383", "oTarget: " + GetName(sTarget.oTarget) + + " is attacking " + GetName(oAttacking)); + // They are attacking someone besides us or we are hidden? + if((oAttacking != OBJECT_INVALID && oAttacking != oCreature) || + GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1398", "Found best sneak attack Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +int ai_GetNearestIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(GetLocalInt(oCreature, AI_RULE_AI_DIFFICULTY)) + { + ai_GetLowestCRIndexNotInAOE(oCreature, fMaxRange, sTargetType, bAlwaysAtk); + } + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1416", "Getting the nearest not in AOE index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget) && !ai_IsInADangerousAOE(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1434", "Found nearest not in AOE Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetNearestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1439", "Getting the nearest not in AOE target."); + string sIndex = IntToString(ai_GetNearestIndexNotInAOE(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetLowestCRIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 100; + sTarget.nBestSecondaryValue = 100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1456", "Getting the lowest CR not in AOE index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && !ai_IsInADangerousAOE(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1463", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1477", "Found lowest CR not in AOE [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetLowestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1482", "Getting the lowest cr not in AOE target."); + string sIndex = IntToString(ai_GetLowestCRIndexNotInAOE(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetHighestCRIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1499", "Getting the highest CR not in AOE index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && !ai_IsInADangerousAOE(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1506", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1520", "Found highest CR not in AOE [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_GetHighestTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1525", "Getting the highest cr not in AOE target."); + string sIndex = IntToString(ai_GetHighestCRIndexNotInAOE(oCreature, fMaxRange, sTargetType, bAlwaysAtk)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +int ai_GetHighestMeleeIndexNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1542", "Getting the highest InMelee not in AOE index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && !ai_IsInADangerousAOE(sTarget.oTarget)) + { + if(ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_MELEE" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1563", "Found highest InMelee not in AOE [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return sTarget.nIndex; +} +object ai_CheckForGroupedTargetNotInAOE(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "1574", "Getting the highest InMelee not in AOE target."); + string sIndex = IntToString(ai_GetHighestMeleeIndexNotInAOE(oCreature, fMaxRange, sTargetType)); + return GetLocalObject(oCreature, sTargetType + sIndex); +} +object ai_GetNearestClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(GetLocalInt(oCreature, AI_RULE_AI_DIFFICULTY)) + { + ai_GetLowestCRClassTarget(oCreature, nClassType, fMaxRange, sTargetType, bAlwaysAtk); + } + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1591", "Getting the nearest class index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckClassType(sTarget.oTarget, nClassType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1598", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1611", "Found nearest class Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetLowestCRClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 100; + sTarget.nBestSecondaryValue = 100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1626", "Getting the lowest CR class index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckClassType(sTarget.oTarget, nClassType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1634", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1648", "Found lowest CR class [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetHighestCRClassTarget(object oCreature, int nClassType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1664", "Getting the highest CR class index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckClassType(sTarget.oTarget, nClassType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1671", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1685", "Found highest CR class [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetNearestRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + if(GetLocalInt(oCreature, AI_RULE_AI_DIFFICULTY)) + { + ai_GetLowestCRRacialTarget(oCreature, nRacialType, fMaxRange, sTargetType, bAlwaysAtk); + } + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1703", "Getting the nearest race index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckRacialType(sTarget.oTarget, nRacialType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1710", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1723", "Found nearest race Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetLowestCRRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = 100; + sTarget.nBestSecondaryValue = 100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1739", "Getting the lowest CR race index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckRacialType(sTarget.oTarget, nRacialType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1746", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1760", "Found lowest CR race [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetHighestCRRacialTarget(object oCreature, int nRacialType, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = sTargetType; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1776", "Getting the highest CR race index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckRacialType(sTarget.oTarget, nRacialType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1783", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter); + sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1797", "Found highest CR race [" + sTargetType + "] Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, sTargetType + IntToString(sTarget.nIndex)); +} +object ai_GetNearestFavoredEnemyTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.nBestValue = -100; + sTarget.nBestSecondaryValue = -100; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + int nRace, nRacialType; + while(nRace < 24) + { + // Find which favored enemies we have. + if(nRace < 1 && GetHasFeat(FEAT_FAVORED_ENEMY_ABERRATION, oCreature)) + { + nRace = 1; + nRacialType = RACIAL_TYPE_ABERRATION; + } + else if(nRace < 2 && GetHasFeat(FEAT_FAVORED_ENEMY_ANIMAL, oCreature)) + { + nRace = 2; + nRacialType = RACIAL_TYPE_ANIMAL; + } + else if(nRace < 3 && GetHasFeat(FEAT_FAVORED_ENEMY_BEAST, oCreature)) + { + nRace = 3; + nRacialType = RACIAL_TYPE_BEAST; + } + else if(nRace < 4 && GetHasFeat(FEAT_FAVORED_ENEMY_CONSTRUCT, oCreature)) + { + nRace = 4; + nRacialType = RACIAL_TYPE_CONSTRUCT; + } + else if(nRace < 5 && GetHasFeat(FEAT_FAVORED_ENEMY_DRAGON, oCreature)) + { + nRace = 5; + nRacialType = RACIAL_TYPE_DRAGON; + } + else if(nRace < 6 && GetHasFeat(FEAT_FAVORED_ENEMY_DWARF, oCreature)) + { + nRace = 6; + nRacialType = RACIAL_TYPE_DWARF; + } + else if(nRace < 7 && GetHasFeat(FEAT_FAVORED_ENEMY_ELEMENTAL, oCreature)) + { + nRace = 7; + nRacialType = RACIAL_TYPE_ELEMENTAL; + } + else if(nRace < 8 && GetHasFeat(FEAT_FAVORED_ENEMY_ELF, oCreature)) + { + nRace = 8; + nRacialType = RACIAL_TYPE_ELF; + } + else if(nRace < 9 && GetHasFeat(FEAT_FAVORED_ENEMY_FEY, oCreature)) + { + nRace = 9; + nRacialType = RACIAL_TYPE_FEY; + } + else if(nRace < 10 && GetHasFeat(FEAT_FAVORED_ENEMY_GIANT, oCreature)) + { + nRace = 10; + nRacialType = RACIAL_TYPE_GIANT; + } + else if(nRace < 11 && GetHasFeat(FEAT_FAVORED_ENEMY_GNOME, oCreature)) + { + nRace = 11; + nRacialType = RACIAL_TYPE_GNOME; + } + else if(nRace < 12 && GetHasFeat(FEAT_FAVORED_ENEMY_GOBLINOID, oCreature)) + { + nRace = 12; + nRacialType = RACIAL_TYPE_HUMANOID_GOBLINOID; + } + else if(nRace < 13 && GetHasFeat(FEAT_FAVORED_ENEMY_HALFELF, oCreature)) + { + nRace = 13; + nRacialType = RACIAL_TYPE_HALFELF; + } + else if(nRace < 14 && GetHasFeat(FEAT_FAVORED_ENEMY_HALFLING, oCreature)) + { + nRace = 14; + nRacialType = RACIAL_TYPE_HALFLING; + } + else if(nRace < 15 && GetHasFeat(FEAT_FAVORED_ENEMY_HALFORC, oCreature)) + { + nRace = 15; + nRacialType = RACIAL_TYPE_HALFORC; + } + else if(nRace < 16 && GetHasFeat(FEAT_FAVORED_ENEMY_HUMAN, oCreature)) + { + nRace = 16; + nRacialType = RACIAL_TYPE_HUMAN; + } + else if(nRace < 17 && GetHasFeat(FEAT_FAVORED_ENEMY_MAGICAL_BEAST, oCreature)) + { + nRace = 17; + nRacialType = RACIAL_TYPE_MAGICAL_BEAST; + } + else if(nRace < 18 && GetHasFeat(FEAT_FAVORED_ENEMY_MONSTROUS, oCreature)) + { + nRace = 18; + nRacialType = RACIAL_TYPE_HUMANOID_MONSTROUS; + } + else if(nRace < 19 && GetHasFeat(FEAT_FAVORED_ENEMY_ORC, oCreature)) + { + nRace = 19; + nRacialType = RACIAL_TYPE_HUMANOID_ORC; + } + else if(nRace < 20 && GetHasFeat(FEAT_FAVORED_ENEMY_OUTSIDER, oCreature)) + { + nRace = 20; + nRacialType = RACIAL_TYPE_OUTSIDER; + } + else if(nRace < 21 && GetHasFeat(FEAT_FAVORED_ENEMY_REPTILIAN, oCreature)) + { + nRace = 21; + nRacialType = RACIAL_TYPE_HUMANOID_REPTILIAN; + } + else if(nRace < 22 && GetHasFeat(FEAT_FAVORED_ENEMY_SHAPECHANGER, oCreature)) + { + nRace = 22; + nRacialType = RACIAL_TYPE_SHAPECHANGER; + } + else if(nRace < 23 && GetHasFeat(FEAT_FAVORED_ENEMY_UNDEAD, oCreature)) + { + nRace = 23; + nRacialType = RACIAL_TYPE_UNDEAD; + } + else if(nRace < 24 && GetHasFeat(FEAT_FAVORED_ENEMY_VERMIN, oCreature)) + { + nRace = 24; + nRacialType = RACIAL_TYPE_VERMIN; + } + else nRace = 25; + if(nRace < 25) + { + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1940", "Getting the nearest favored race index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget) && ai_CheckRacialType(sTarget.oTarget, nRacialType)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "1947", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) + + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + } + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "1962", "Found nearest favored race Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, AI_ENEMY + IntToString(sTarget.nIndex)); +} +object ai_GetFlankTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE) +{ + int nCnt = 1, nInMelee, nHighestMelee; + string sCnt = "1"; + float fAllyRange; + object oTarget, oAlly = GetLocalObject(oCreature, AI_ALLY + sCnt); + while(oAlly != OBJECT_INVALID) + { + fAllyRange = GetLocalFloat(oCreature, AI_ALLY_RANGE + sCnt); + if(AI_DEBUG) ai_Debug("0i_combat", "1974", "Getting Ally being Flanked Index: " + sCnt + " " + + GetName(oAlly) + " fAllyRange: " + FloatToString(fAllyRange, 0, 2) + + " fMaxRange: " + FloatToString(fMaxRange, 0, 2)); + if(fAllyRange <= fMaxRange) + { + nInMelee = GetLocalInt(oCreature, AI_ALLY_MELEE + sCnt); + if(AI_DEBUG) ai_Debug("0i_combat", "1980", "nInMelee: " + IntToString(nInMelee)); + if(!GetIsDead(oAlly) && nInMelee > nHighestMelee) + { + oTarget = ai_GetEnemyAttackingMyAlly(oCreature, oAlly, fMaxRange); + if(oTarget != OBJECT_INVALID) nHighestMelee = nInMelee; + } + } + sCnt = IntToString(++nCnt); + oAlly = GetLocalObject(oCreature, AI_ALLY + sCnt); + } + // If we do not have a good target then lets see if there are more targets. + if(oTarget == OBJECT_INVALID) + { + // If we just checked within melee then lets check what we can see if + // we can move around in combat. + if (fMaxRange == AI_RANGE_MELEE && ai_CanIMoveInCombat(oCreature)) + { + oTarget = ai_GetFlankTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + } + } + if(AI_DEBUG) ai_Debug("0i_combat", "2000", "oTarget " + GetName(oTarget) + + " is attacking " + GetName(oAlly)); + return oTarget; +} +object ai_GetRangedTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, int bAlwaysAtk = TRUE) +{ + struct stTarget sTarget; + sTarget.fNearestRange = fMaxRange + 1.0; + sTarget.fNearestSecondaryRange = sTarget.fNearestRange; + sTarget.sTargetType = AI_ENEMY; + int nCounter = 1; + string sCounter = "1"; + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + while(sTarget.oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "2037", "Getting the nearest ranged index: " + + sCounter + " " + GetName(sTarget.oTarget) + + " Seen: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter)) + + " GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget))); + if(GetLocalInt(oCreature, AI_ENEMY_PERCEIVED + sCounter) && + !GetIsDead(sTarget.oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "2044", "bAlwaysAtk: " + IntToString(bAlwaysAtk)); + if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) && + ai_TargetIsInRangeofCreature(oCreature, AI_ENEMY, sCounter, fMaxRange) && + ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget)) + { + if(ai_GetIsRangeWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, sTarget.oTarget))) + { + sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter); + } + } + } + sCounter = IntToString(++nCounter); + sTarget.oTarget = GetLocalObject(oCreature, AI_ENEMY + sCounter); + } + // If we do not have a normal target then use our best secondary target. + if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex; + if(AI_DEBUG) ai_Debug("0i_combat", "2060", "Found nearest ranged Index: " + IntToString(sTarget.nIndex)); + return GetLocalObject(oCreature, AI_ENEMY + IntToString(sTarget.nIndex)); +} +object ai_GetBestTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget != OBJECT_INVALID) return oPCTarget; + string sIndex; + // Are we in melee? If so try to get the weakest enemy in melee. + if(nInMelee > 0) + { + if(ai_CanIMoveInCombat(oCreature)) + { + sIndex = IntToString(ai_GetLowestCRIndex(oCreature, AI_RANGE_MELEE)); + } + else sIndex = IntToString(ai_GetNearestIndex(oCreature, AI_RANGE_MELEE)); + } + // If not then lets go find someone to attack! + else + { + // If we are not in melee then we should get the nearest enemy. + sIndex = IntToString(ai_GetNearestIndexNotInAOE(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + /* Lets stay out of bad AOE's. + // If we didn't get a target then get any target within range. + if(sIndex == "0") + { + sIndex = IntToString(ai_GetLowestCRIndex(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + } */ + } + object oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("0i_combat", "2048", GetName(oTarget) + " is the best target for melee combat!"); + return oTarget; +} +object ai_GetNearestTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget != OBJECT_INVALID) return oPCTarget; + string sIndex; + // Are we in melee? If so try to get the nearest enemy in melee. + if(nInMelee > 0) sIndex = IntToString(ai_GetNearestIndex(oCreature, AI_RANGE_MELEE)); + // If not then lets go find someone to attack! + else + { + // Get the nearest enemy. + sIndex = IntToString(ai_GetNearestIndexNotInAOE(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + // If we didn't get a target then get any target within range. + if(sIndex == "0") + { + sIndex = IntToString(ai_GetNearestIndex(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + } + } + object oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("0i_combat", "2024", GetName(oTarget) + " is the nearest target for melee combat!"); + return oTarget; +} +object ai_GetLowestCRTargetForMeleeCombat(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget != OBJECT_INVALID) return oPCTarget; + string sIndex; + // Are we in melee? If so try to get the weakest enemy in melee. + if(nInMelee > 0) sIndex = IntToString(ai_GetLowestCRIndex(oCreature, AI_RANGE_MELEE)); + // If not then lets go find someone to attack! + else + { + // Get the weakest combat rated enemy. + sIndex = IntToString(ai_GetLowestCRIndexNotInAOE(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + /* Lets stay out of bad AOE's. + // If we didn't get a target then get any target within range. + if(sIndex == "0") + { + sIndex = IntToString(ai_GetLowestCRIndex(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk)); + } */ + } + object oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("0i_combat", "2048", GetName(oTarget) + " is the weakest target for melee combat!"); + return oTarget; +} +object ai_GetHighestCRTargetForMeleeCombat(object oCreature, int nInMelee) +{ + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget != OBJECT_INVALID) return oPCTarget; + string sIndex; + // Are we in melee? If so try to get the weakest enemy in melee. + if(nInMelee > 0) sIndex = IntToString(ai_GetHighestCRIndex(oCreature, AI_RANGE_MELEE)); + // If not then lets go find someone to attack! + else + { + // Get the weakest combat rated enemy. + sIndex = IntToString(ai_GetHighestCRIndexNotInAOE(oCreature, AI_RANGE_PERCEPTION)); + /* Lets stay out of bad AOE's. + // If we didn't get a target then get any target within range. + if(sIndex == "0") sIndex = IntToString(ai_GetHighestCRIndex(oCreature)); + */ + } + object oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("0i_combat", "2070", GetName(oTarget) + " is the strongest target for melee combat!"); + return oTarget; +} +object ai_GetEnemyAttackingMe(object oCreature, float fMaxRange = AI_RANGE_MELEE) +{ + int nCtr = 1; + float fDistance; + string sCtr = "1"; + object oAttacked; + object oEnemy = GetLocalObject(oCreature, AI_ENEMY + "1"); + while(oEnemy != OBJECT_INVALID) + { + if(!ai_Disabled(oEnemy)) + { + fDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + sCtr); + if(AI_DEBUG) ai_Debug("0i_combat", "2084", "Getting Enemy Attacking Me: " + sCtr + " " + + GetName(oEnemy) + " fTargetRange: " + FloatToString(fDistance, 0, 2) + + " fMaxRange: " + FloatToString(fMaxRange, 0, 2) + " Attacking: " + + GetName(ai_GetAttackedTarget(oEnemy))); + if(fDistance <= fMaxRange) + { + oAttacked = ai_GetAttackedTarget(oEnemy); + // If an enemy isn't attacking someone we must assume we are next! + if(oAttacked == oCreature || oAttacked == OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "2095", "Enemy attacking me: " + GetName(oEnemy) + " has attacked: " + GetName(ai_GetAttackedTarget(oEnemy))); + return oEnemy; + } + } + } + sCtr = IntToString(++nCtr); + oEnemy = GetLocalObject(oCreature, AI_ENEMY + sCtr); + } + return OBJECT_INVALID; +} +object ai_GetEnemyAttackingMyAlly(object oCreature, object oAlly, float fMaxRange = AI_RANGE_MELEE) +{ + int nCtr = 1, nIndex, nDIndex; + int bIngnoreAssociates = ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES); + float fEnemyRange, fNearestEnemyRange = fMaxRange + 1.0; + float fNearestDEnemyRange = fMaxRange + 1.0; + string sCtr = "1"; + object oAttacked; + object oEnemy = GetLocalObject(oCreature, AI_ENEMY + "1"); + while(oEnemy != OBJECT_INVALID) + { + fEnemyRange = GetLocalFloat(oCreature, AI_ENEMY_RANGE + sCtr); + if(AI_DEBUG) ai_Debug("0i_combat", "2117", "Getting Enemy Attacking Ally:" + + GetName(oAlly) + ": " + sCtr + " InMelee:" + + GetName(oEnemy) + " fEnemyRange: " + FloatToString(fEnemyRange, 0, 2) + + " fMaxRange: " + FloatToString(fMaxRange, 0, 2) + " Attacking: " + + GetName(ai_GetAttackedTarget(oEnemy))); + if(fEnemyRange <= fMaxRange) + { + oAttacked = ai_GetAttackedTarget(oEnemy); + if(AI_DEBUG) ai_Debug("0i_combat", "2125", "Enemy attacking " + + GetName(oAlly) + ": " + GetName(oEnemy) + + " has attacked: " + GetName(ai_GetAttackedTarget(oEnemy))); + // If an enemy isn't attacking someone we must assume we are next! + if(oAttacked == oAlly) + { + // Lets put any disabled targets in its own group, if we + // ignore associates lets put them here as well. + if(GetLocalInt(oCreature, AI_ENEMY_DISABLED + sCtr) || + (bIngnoreAssociates && GetAssociateType(oEnemy))) + { + if(fEnemyRange < fNearestDEnemyRange) + { + fNearestDEnemyRange = fEnemyRange; + nDIndex = nCtr; + } + } + else if(fEnemyRange < fNearestEnemyRange) + { + fNearestEnemyRange = fEnemyRange; + nIndex = nCtr; + } + } + } + sCtr = IntToString(++nCtr); + oEnemy = GetLocalObject(oCreature, AI_ENEMY + sCtr); + } + // If we do not have a good target then lets see if there are more targets. + if(nIndex == 0 && nDIndex != 0) + { + // If we just checked within melee then lets check what we can see. + if (fMaxRange == AI_RANGE_MELEE) return ai_GetEnemyAttackingMyAlly(oCreature, oAlly, AI_RANGE_PERCEPTION); + else nIndex = nDIndex; + } + return GetLocalObject(oCreature, AI_ENEMY + IntToString(nIndex)); +} +int ai_GetNumOfEnemiesInRange(object oCreature, float fMaxRange = AI_RANGE_MELEE) +{ + int nNumOfEnemies, nCnt = 1; + float fDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + "1"); + while(fDistance != 0.0) + { + if(fDistance < fMaxRange) nNumOfEnemies ++; + fDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + IntToString(++nCnt)); + } + if(AI_DEBUG) ai_Debug("0i_combat", "2459", IntToString (nNumOfEnemies) + " enemies within " + FloatToString(fMaxRange, 0, 2) + " meters."); + return nNumOfEnemies; +} +object ai_GetAllyBuffTarget(object oCreature, int nSpell, float fMaxRange = AI_RANGE_BATTLEFIELD) +{ + // Make sure we don't over extend our movement running across the + // battlefield to cast a spell on someone does not look good. + float fNearestEnemy = GetDistanceBetween(oCreature, GetLocalObject(oCreature, AI_ENEMY_NEAREST)) - 3.0f; + // If we are in melee then extend to melee incase an ally is just past the enemy. + if(fNearestEnemy <= AI_RANGE_MELEE) fNearestEnemy = AI_RANGE_MELEE; + if(fMaxRange > fNearestEnemy) fMaxRange = fNearestEnemy; + // Now lets get the best target based on the spell data in ai_spells.2da + string sBuffTarget = Get2DAString("ai_spells", "Buff_Target", nSpell); + if(AI_DEBUG) ai_Debug("0i_combat", "2596", "sBuffTarget: " + sBuffTarget + " fMaxRange: " + FloatToString(fMaxRange, 0, 2)); + if(sBuffTarget == "0") return oCreature; + if(sBuffTarget == "1") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_STRENGTH, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "2") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_DEXTERITY, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "3") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_CONSTITUTION, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "4") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_INTELLIGENCE, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "5") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_WISDOM, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "6") + return ai_BuffHighestAbilityScoreTarget(oCreature, nSpell, ABILITY_CHARISMA, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "7") + return ai_BuffLowestACTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "8") + return ai_BuffLowestACWithOutACBonus(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "9") + return ai_BuffHighestAttackTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "10") + return ai_BuffMostWoundedTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "11") + return ai_BuffLowestFortitudeSaveTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "12") + return ai_BuffLowestReflexSaveTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "13") + return ai_BuffLowestWillSaveTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + else if(sBuffTarget == "14") + return ai_BuffLowestSaveTarget(oCreature, nSpell, "", fMaxRange, AI_ALLY); + return OBJECT_INVALID; +} + +//****************************************************************************** +//******************** OTHER COMBAT FUNCTIONS ******************************** +//****************************************************************************** + +int ai_GetCurrentRound(object oCreature) +{ + int nRound = GetLocalInt(oCreature, AI_ROUND) + 1; + SetLocalInt(oCreature, AI_ROUND, nRound); + if(AI_DEBUG) ai_Debug("0i_combat", "2471", "nRound: " + IntToString(nRound)); + return nRound; +} +int ai_GetDifficulty(object oCreature) +{ + int nAdjustment = GetLocalInt(oCreature, AI_DIFFICULTY_ADJUSTMENT); + int nDifficulty = GetLocalInt(oCreature, AI_ENEMY_POWER) - GetLocalInt(oCreature, AI_ALLY_POWER) + 13 + nAdjustment; + if(nDifficulty < 1) nDifficulty = 1; + if(AI_DEBUG) ai_Debug("0i_combat", "2474", "(Difficulty: Enemy Power: " + IntToString(GetLocalInt(oCreature, AI_ENEMY_POWER)) + + " - Ally Power: " + IntToString(GetLocalInt(oCreature, AI_ALLY_POWER)) + + ") + 13 + nAdj: " + IntToString(nAdjustment) + + " = " + IntToString(nDifficulty) + "(Min of 1)"); + return nDifficulty; +} +int ai_GetMyCombatRating(object oCreature) +{ + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + int nAtkBonus = GetBaseAttackBonus(oCreature); + if(GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) && ai_GetIsFinesseWeapon(oCreature, oWeapon)) + { + nAtkBonus += GetAbilityModifier(ABILITY_DEXTERITY, oCreature); + } + else nAtkBonus += GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(ai_GetIsMeleeWeapon(oWeapon)) nAtkBonus += ai_GetWeaponAtkBonus(oWeapon); + if(AI_DEBUG) ai_Debug("0i_combat", "2496", "GetMyCombatRating (nAtkBonus: " + IntToString(nAtkBonus) + + " nAC: " + IntToString(GetAC(oCreature)) + " - 10) / 2 = " + + IntToString((nAtkBonus + GetAC(oCreature) - 10) / 2)); + return(nAtkBonus + GetAC(oCreature) - 10) / 2; +} +object ai_GetAttackedTarget(object oCreature, int bPhysical = TRUE, int bSpell = FALSE) +{ + object oTarget = GetAttackTarget(oCreature); + if(!GetIsObjectValid(oTarget) && bPhysical) oTarget = GetLocalObject(oCreature, AI_ATTACKED_PHYSICAL); + if(!GetIsObjectValid(oTarget) && bSpell) oTarget = GetLocalObject(oCreature, AI_ATTACKED_SPELL); + if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget)) return OBJECT_INVALID; + return oTarget; +} +int ai_CheckClassType(object oTarget, int nClassType) +{ + int nCnt = 1, nClass = GetClassByPosition(1, oTarget); + // We check for the group class types. + if(nClassType < 0) + { + while(nCnt <= AI_MAX_CLASSES_PER_CHARACTER) + { + int nCaster = StringToInt(Get2DAString("classes", "SpellCaster", nClass)); + if(nClassType == AI_CLASS_TYPE_WARRIOR && !nCaster) return TRUE; + else if(nClassType == AI_CLASS_TYPE_CASTER && nCaster) return TRUE; + int nSpellType = StringToInt(Get2DAString("classes", "Arcane", nClass)); + if(nClassType == AI_CLASS_TYPE_ARCANE && nSpellType) return TRUE; + else if(nClassType == AI_CLASS_TYPE_DIVINE && !nSpellType) return TRUE; + nClass = GetClassByPosition(++nCnt, oTarget); + } + } + // Checks for normal classes. + else + { + while(nCnt <= AI_MAX_CLASSES_PER_CHARACTER) + { + if(nClass == nClassType) return TRUE; + nClass = GetClassByPosition(++nCnt, oTarget); + } + } + return FALSE; +} +int ai_CheckRacialType(object oTarget, int nRacialType) +{ + int nRace = GetRacialType(oTarget); + if(nRacialType == nRace) return TRUE; + else if(nRacialType == AI_RACIAL_TYPE_ANIMAL_BEAST) + { + if(nRace == RACIAL_TYPE_ANIMAL || + nRace == RACIAL_TYPE_BEAST || + nRace == RACIAL_TYPE_MAGICAL_BEAST) return TRUE; + } + else if(nRacialType == AI_RACIAL_TYPE_HUMANOID) + { + switch (nRace) + { + case RACIAL_TYPE_DWARF : + case RACIAL_TYPE_ELF : + case RACIAL_TYPE_GNOME : + case RACIAL_TYPE_HALFELF : + case RACIAL_TYPE_HALFLING : + case RACIAL_TYPE_HALFORC : + case RACIAL_TYPE_HUMAN : + case RACIAL_TYPE_HUMANOID_GOBLINOID : + case RACIAL_TYPE_HUMANOID_MONSTROUS : + case RACIAL_TYPE_HUMANOID_ORC : + case RACIAL_TYPE_HUMANOID_REPTILIAN : + return TRUE; + } + } + return FALSE; +} +void ai_SetNormalAppearance(object oCreature) +{ + if(!ai_GetHasEffectType(oCreature, EFFECT_TYPE_POLYMORPH)) + { + int nForm = GetAppearanceType(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "2729", GetName(oCreature) + " form: " + IntToString(nForm)); + SetLocalInt(oCreature, AI_NORMAL_FORM, nForm + 1); + } +} +int ai_GetNormalAppearance(object oCreature) +{ + int nForm = GetLocalInt(oCreature, AI_NORMAL_FORM) - 1; + if(nForm == -1) + { + ai_SetNormalAppearance(oCreature); + nForm = GetLocalInt(oCreature, AI_NORMAL_FORM) - 1; + } + return nForm; +} +struct stClasses ai_GetFactionsClasses(object oCreature, int bEnemy = TRUE, float fMaxRange = AI_RANGE_BATTLEFIELD) +{ + struct stClasses sCount; + int nCnt = 1, nPosition, nClass, nLevels; + object oTarget; + if(bEnemy) oTarget = ai_GetNearestEnemy(oCreature, 1, 7, 7); + else oTarget = ai_GetNearestAlly(oCreature, 1, 7, 7); + while(oTarget != OBJECT_INVALID && GetDistanceBetween(oTarget, oCreature) <= fMaxRange) + { + for(nPosition = 1; nPosition <= AI_MAX_CLASSES_PER_CHARACTER; nPosition++) + { + nClass = GetClassByPosition(nPosition, oTarget); + nLevels = GetLevelByPosition(nPosition, oTarget); + if(nClass == CLASS_TYPE_ANIMAL || + nClass == CLASS_TYPE_BARBARIAN || + nClass == CLASS_TYPE_COMMONER || + nClass == CLASS_TYPE_CONSTRUCT || + nClass == CLASS_TYPE_ELEMENTAL || + nClass == CLASS_TYPE_FIGHTER || + nClass == CLASS_TYPE_GIANT || + nClass == CLASS_TYPE_HUMANOID || + nClass == CLASS_TYPE_MONSTROUS || + nClass == CLASS_TYPE_PALADIN || + nClass == CLASS_TYPE_RANGER || + nClass == CLASS_TYPE_ROGUE || + nClass == CLASS_TYPE_VERMIN || + nClass == CLASS_TYPE_MONK || + nClass == CLASS_TYPE_SHAPECHANGER) + { + sCount.FIGHTERS += 1; + sCount.FIGHTER_LEVELS += nLevels; + } + else if(nClass == CLASS_TYPE_CLERIC || + nClass == CLASS_TYPE_DRUID) + { + sCount.CLERICS += 1; + sCount.CLERIC_LEVELS += nLevels; + } + else if(nClass == CLASS_TYPE_BARD || + nClass == CLASS_TYPE_FEY || + nClass == CLASS_TYPE_SORCERER || + nClass == CLASS_TYPE_WIZARD) + { + sCount.MAGES += 1; + sCount.MAGE_LEVELS += nLevels; + } + else if(nClass == CLASS_TYPE_ABERRATION || + nClass == CLASS_TYPE_DRAGON || + nClass == 29 || //oozes + nClass == CLASS_TYPE_MAGICAL_BEAST || + nClass == CLASS_TYPE_OUTSIDER) + { + sCount.MONSTERS += 1; + sCount.MONSTER_LEVELS += nLevels; + } + sCount.TOTAL_LEVELS += nLevels; + } + sCount.TOTAL += 1; + if(bEnemy) oTarget = ai_GetNearestEnemy(oCreature, ++nCnt, 7, 7); + else oTarget = ai_GetNearestAlly(oCreature, ++nCnt, 7, 7); + } + if(AI_DEBUG) ai_Debug("0i_combat", "2627", "Enemy: " + IntToString(bEnemy) + " fMaxRange: " + FloatToString(fMaxRange, 0, 2) + + " CLERICS: " + IntToString(sCount.CLERICS) + "(" + IntToString(sCount.CLERIC_LEVELS) + + ") FIGHTERS: " +IntToString(sCount.FIGHTERS) + "(" + IntToString(sCount.FIGHTER_LEVELS) + + ") MAGES: " +IntToString(sCount.MAGES) + "(" + IntToString(sCount.MAGE_LEVELS) + + ") MONSTERS: " +IntToString(sCount.MONSTERS) + "(" + IntToString(sCount.MONSTER_LEVELS) + + ") TOTALS: " +IntToString(sCount.TOTAL) + "(" + IntToString(sCount.TOTAL_LEVELS)); + return sCount; +} +string ai_GetMostDangerousClass(struct stClasses stCount) +{ + string sClass; + // Lets weight the fighter levels 30% higher. + int nFighter =((stCount.FIGHTER_LEVELS) * 13)/10; + if(nFighter >= stCount.CLERIC_LEVELS) + { + if(nFighter >= stCount.MAGE_LEVELS) + { + if(nFighter >= stCount.MONSTER_LEVELS) return "FIGHTER"; + else return "MONSTER"; + } + else if(stCount.MAGE_LEVELS >= stCount.MONSTER_LEVELS) return "MAGE"; + else return "MONSTER"; + } + else if(stCount.CLERIC_LEVELS >= stCount.MAGE_LEVELS) + { + if(stCount.CLERIC_LEVELS >= stCount.MONSTER_LEVELS) return "CLERIC"; + else return "MONSTER"; + } + else if(stCount.MAGE_LEVELS >= stCount.MONSTER_LEVELS) return "MAGE"; + else return "MONSTER"; + return ""; +} +void ai_EquipBestWeapons(object oCreature, object oTarget = OBJECT_INVALID) +{ + // Lets not check for weapons on creatures that can't use them! + int nRacialType = GetRacialType(oCreature); + if(nRacialType == RACIAL_TYPE_ANIMAL || + nRacialType == RACIAL_TYPE_DRAGON || + nRacialType == RACIAL_TYPE_MAGICAL_BEAST || + nRacialType == RACIAL_TYPE_OOZE || + nRacialType == RACIAL_TYPE_VERMIN) return; + //if(Polymorphed()) return; + if(AI_DEBUG) ai_Debug("0i_combat", "2669", GetName(OBJECT_SELF) + " is equiping best weapon!"); + // Determine if I am wielding a ranged weapon, melee weapon, or none. + int bIsWieldingRanged = ai_HasRangedWeaponWithAmmo(oCreature); + int bIsWieldingMelee = ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND)); + if(AI_DEBUG) ai_Debug("0i_combat", "2673", "bIsWieldingRanged: " + IntToString(bIsWieldingRanged) + + " bIsWieldingMelee: " + IntToString(bIsWieldingMelee)); + // If we are hidden then change to a melee weapon so we can move in to attack. + if(ai_GetIsHidden(oCreature)) + { + // Equip a melee weapon unless we already have one. + if(!bIsWieldingMelee) ai_EquipBestMeleeWeapon(oCreature, oTarget); + return; + } + // Equip the appropriate weapon for the distance of the enemy. + int nEnemyGroup = ai_GetNumOfEnemiesInGroup(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "2684", GetName(oCreature) + " has " + IntToString(nEnemyGroup) + " enemies within 5.0f them! PointBlank: " + + IntToString(GetHasFeat(FEAT_POINT_BLANK_SHOT, oCreature))); + // We are in melee combat. + if(nEnemyGroup > 0) + { + if(bIsWieldingRanged) + { + // We have the point blank shot feat or there are more than one enemy on us. + // Note: Point Blank shot feat is bad once we have more than one enemy on us. + if(!GetHasFeat(FEAT_POINT_BLANK_SHOT, oCreature) || nEnemyGroup > 1) + { + // If I'm not using a melee weapon. + if(!bIsWieldingMelee) + { + ai_EquipBestMeleeWeapon(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "2699", GetName(oCreature) + " is equiping melee weapon due to close enemies!"); + } + } + } + } + // We are not in melee range. + else + { + if(AI_DEBUG) ai_Debug("0i_combat", "2707", GetName(oCreature) + " is not in melee combat with an enemy!"); + // If are at range with the enemy then equip a ranged weapon. + if(!bIsWieldingRanged) + { + ai_EquipBestRangedWeapon(oTarget); + // Make sure that they equiped a range weapon. + bIsWieldingRanged = ai_HasRangedWeaponWithAmmo(oCreature); + bIsWieldingMelee = ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature)); + if(AI_DEBUG) ai_Debug("0i_combat", "2719", GetName(oCreature) + " is attempting to equip a ranged weapon: " + IntToString(bIsWieldingRanged)); + // If we equiped a ranged weapon then drop out. + } + } + // We don't have a weapon out so equip one! We are in combat! + if(!bIsWieldingRanged && !bIsWieldingMelee) ai_EquipBestMeleeWeapon(OBJECT_INVALID); +} +int ai_EquipBestMeleeWeapon(object oCreature, object oTarget = OBJECT_INVALID) +{ + if(ai_GetAIMode(oCreature, AI_MODE_EQUIP_WEAPON_OFF)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_combat", "3049", GetName(oCreature) + " is equiping best melee weapon!"); + float fItemPower, fOffItemPower, fRightPower, fLeftPower, f2HandedPower; + int nItemPower, nShieldPower, nShieldValue, nItemValue, nRightValue; + int n2HandedValue, nLeftValue, bTwoWeaponUser; + int nMaxItemValue = ai_GetMaxItemValueThatCanBeEquiped(GetHitDice(oCreature)); + if(AI_DEBUG) ai_Debug("0i_combat", "3054", "nMaxItemValue: " + IntToString(nMaxItemValue)); + bTwoWeaponUser = GetHasFeat(374/*FEAT_DUAL_WIELD*/, oCreature) || GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oCreature); + object oShield = OBJECT_INVALID; + object oRight = OBJECT_INVALID; + object oLeft = OBJECT_INVALID; + object o2Handed = OBJECT_INVALID; + object o2HandedHand = OBJECT_INVALID; + object oRightHand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); + if(oRightHand != OBJECT_INVALID) + { + // Setup the item in our right hand's avg dmg and gold value as our base. + if(ai_GetIsTwoHandedWeapon(oRightHand, oCreature)) + { + if(ai_GetIsDoubleWeapon(oRightHand)) + { + f2HandedPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRightHand, TRUE, FALSE, oRightHand); + } + else f2HandedPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRightHand, TRUE); + n2HandedValue = GetGoldPieceValue(oRightHand); + if(AI_DEBUG) ai_Debug("0i_combat", "3073", " 2Handed oRightHand: " + GetName(oRightHand) + + " f2HandPower: " + FloatToString(f2HandedPower, 0, 2) + + " n2HandedValue: " + IntToString(n2HandedValue)); + } + else if(ai_GetIsSingleHandedWeapon(oRightHand, oCreature)) + { + fRightPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRightHand); + nRightValue = GetGoldPieceValue(oRightHand); + if(AI_DEBUG) ai_Debug("0i_combat", "3081", " 1Handed oRightHand: " + GetName(oRightHand) + + " fRightPower: " + FloatToString(fRightPower, 0, 2) + + " nRightValue: " + IntToString(nRightValue)); + } + } + object oLeftHand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); + if(oLeftHand != OBJECT_INVALID) + { + // Setup the item in our left hand's Shield AC and gold value as our base. + if(ai_GetIsShield(oLeftHand)) + { + nShieldPower = ai_SetShieldAC(oCreature, oLeftHand); + nShieldValue = GetGoldPieceValue(oLeftHand); + if(AI_DEBUG) ai_Debug("0i_combat", "3098", " Shield oLeftHand: " + GetName(oLeftHand) + + " fShieldPower: " + IntToString(nShieldPower) + + " nShieldValue: " + IntToString(nShieldValue)); + } + // Setup the item in our left hand's avg dmg and gold value as our base. + else + { + fLeftPower = ai_GetMeleeWeaponAvgDmg(oCreature, oLeftHand, FALSE, TRUE); + nLeftValue = GetGoldPieceValue(oLeftHand); + if(AI_DEBUG) ai_Debug("0i_combat", "3103", " 1Handed oLeftHand: " + GetName(oLeftHand) + + " fLeftPower: " + FloatToString(fLeftPower, 0, 2) + + " nLeftValue: " + IntToString(nLeftValue)); + } + } + int nWeaponSize, nType, nCreatureSize = GetCreatureSize(oCreature); + // Get the best weapons they have in their inventory. + object oItem = GetFirstItemInInventory(oCreature); + // If they don't have any items then lets stop, we can't equip a weapon/shield. + if(oItem == OBJECT_INVALID) return FALSE; + while(oItem != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3114", GetName(oItem) + " MeleeWeapon: " + + IntToString(ai_GetIsMeleeWeapon(oItem)) + " Proficient: " + + IntToString(ai_GetIsProficientWith(oCreature, oItem)) + + " Identified: " + IntToString(GetIdentified(oItem))); + if(ai_GetIsProficientWith(oCreature, oItem) && + GetIdentified(oItem) && ai_CheckIfCanUseItem(oCreature, oItem)) + { + nItemValue = GetGoldPieceValue(oItem); + if(AI_DEBUG) ai_Debug("0i_combat", "3122", " nItemValue: " + IntToString(nItemValue)); + if(!GetLocalInt(GetModule(), AI_RULE_ILR) || nMaxItemValue >= nItemValue) + { + if(ai_GetIsShield(oItem)) + { + nItemPower = ai_SetShieldAC(oCreature, oItem); + if(nItemPower > nShieldPower || + (nItemPower == nShieldPower && nItemValue > nShieldValue)) + { oShield = oItem; nShieldPower = nItemPower; nShieldValue = nItemValue; } + } + else if(ai_GetIsMeleeWeapon(oItem)) + { + // Make sure the creature and weapon are close enough in size. + // Can wield a weapon up to one size larger than their size. + // Can wield a weapon down to two sizes smaller than their size. + nType = GetBaseItemType(oItem); + nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nType)); + if(nWeaponSize >= nCreatureSize - 2 && nWeaponSize <= nCreatureSize + 1) + { + // Get item avg damage based on if it is 2handed or 1handed. + if(ai_GetIsSingleHandedWeapon(oItem, oCreature)) + { + fItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oItem); + fOffItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oItem, FALSE, TRUE); + // If the new weapon is better than the weapon in our right hand. + if(fItemPower > fRightPower || + (fItemPower == fRightPower && nItemValue > nRightValue)) + { + // We need to check if the weapon in the right hand is + // better than the weapon in the left hand since we are + // replacing our right hand weapon. + // Note: we must find out if we have selected a weapon for the + // right hand i.e. oRight or the best weapon is in our + // right hand i.e. oRightHand! + fOffItemPower = 0.0; + if(oRight != OBJECT_INVALID && ai_GetIsSingleHandedWeapon(oRight, oCreature)) + { + fOffItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRight, FALSE, TRUE); + } + else if(oRightHand != OBJECT_INVALID && ai_GetIsSingleHandedWeapon(oRightHand, oCreature)) + { + fOffItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRightHand, FALSE, TRUE); + } + // If the right hand weapon is better than the weapon in our left hand. + if(fOffItemPower > fLeftPower || (fOffItemPower > 0.0 && + fOffItemPower == fLeftPower && nRightValue > nLeftValue)) + { + if(oRight != OBJECT_INVALID) oLeft = oRight; + else oLeft = oRightHand; + fLeftPower = fOffItemPower; + nLeftValue = nRightValue; + } + oRight = oItem; + fRightPower = fItemPower; + nRightValue = nItemValue; + } + // If the new weapon is better than the weapon in our left hand. + else if(fOffItemPower > fLeftPower || + (fOffItemPower == fLeftPower && nItemValue > nLeftValue)) + { oLeft = oItem; fLeftPower = fOffItemPower; nLeftValue = nItemValue; } + } + else if(ai_GetIsTwoHandedWeapon(oItem, oCreature)) + { + if(ai_GetIsDoubleWeapon(oItem)) + { + fItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oItem, TRUE, FALSE, oItem); + } + else fItemPower = ai_GetMeleeWeaponAvgDmg(oCreature, oItem, TRUE); + // If the new weapon is better than the selected weapon. + if(fItemPower > f2HandedPower || + (fItemPower == f2HandedPower && nItemValue > n2HandedValue)) + { + o2Handed = oItem; + f2HandedPower = fItemPower; + n2HandedValue = nItemValue; + } + } + } + } + } + } + oItem = GetNextItemInInventory(); + } + if(AI_DEBUG) ai_Debug("0i_combat", "3197", "oRight: " + GetName(oRight) + " oLeft:" + + GetName(oLeft) + " oShield: " + GetName(oShield) + + "o2Handed: " + GetName(o2Handed)); + // First check for two weapons first. + if(bTwoWeaponUser && oRight != OBJECT_INVALID && oLeft != OBJECT_INVALID) + { + fRightPower = ai_GetMeleeWeaponAvgDmg(oCreature, oRight, FALSE, FALSE, oLeft); + fRightPower += ai_GetMeleeWeaponAvgDmg(oCreature, oLeft, FALSE, TRUE); + if(AI_DEBUG) ai_Debug("0i_combat", "3205", " Right/Left Power: " + + FloatToString(fRightPower, 0, 2) + " 2HandedPower: " + + FloatToString(f2HandedPower, 0, 2)); + if(fRightPower > f2HandedPower) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3210", GetName(oCreature) + " is equiping " + + GetName(oRight) + " in the right hand and " + GetName(oLeft) + + " in the left hand."); + ActionEquipItem(oRight, INVENTORY_SLOT_RIGHTHAND); + ActionEquipItem(oLeft, INVENTORY_SLOT_LEFTHAND); + return TRUE; + } + } + if(f2HandedPower > fRightPower && o2Handed != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3220", GetName(oCreature) + " is equiping " + + GetName(o2Handed) + " in both hands."); + ActionEquipItem(o2Handed, INVENTORY_SLOT_RIGHTHAND); + return TRUE; + } + // Now lets just equip the best weapon for the right hand. + if(oRight != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3228", GetName(oCreature) + " is equiping " + + GetName(oRight) + " in the right hand. "); + ActionEquipItem(oRight, INVENTORY_SLOT_RIGHTHAND); + } + // Make sure we are not equiping a 2handed weapon and + // If not can we equip a shield? + if((oRight == OBJECT_INVALID || ai_GetIsSingleHandedWeapon(oRight, oCreature) || + !ai_GetIsTwoHandedWeapon(oRightHand, oCreature)) && + oShield != OBJECT_INVALID && GetHasFeat(FEAT_SHIELD_PROFICIENCY, oCreature)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3238", GetName(oCreature) + " is equiping " + + GetName(oShield) + " in the left hand."); + ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); + return TRUE; + } + // Finally if we don't have a weapon to equip so check to see if we are + // holding a bow. + else if(oRight == OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3247", GetName(oCreature) + " did not equip a melee weapon"); + // We couldn't find a melee weapon but we are looking to go into melee + // I'm holding a ranged weapon! We better put it up. + if(GetWeaponRanged(oRightHand)) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3252", GetName(oCreature) + " is unequiping " + GetName(oRightHand)); + ActionUnequipItem(oRightHand); + return TRUE; + } + } + if(AI_DEBUG) ai_Debug("0i_combat", "3257", GetName(oCreature) + " is not equiping a weapon!"); + return FALSE; +} +int ai_EquipBestRangedWeapon(object oCreature, object oTarget = OBJECT_INVALID) +{ + if(ai_GetAIMode(oCreature, AI_MODE_EQUIP_WEAPON_OFF)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_combat", "3267", GetName(oCreature) + " is looking for best ranged weapon!"); + int nAmmo, nAmmoSlot, nBestType1, nBestType2, nType, nFeat, nItemValue, nRangedValue; + int nMaxItemValue = ai_GetMaxItemValueThatCanBeEquiped(GetHitDice(oCreature)); + string sAmmo; + object oRightHand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + if(oRightHand != OBJECT_INVALID && ai_GetIsRangeWeapon(oRightHand)) + { + // Setup the item in our right hand as our base gold value to check against. + if(ai_GetIsRangeWeapon(oRightHand)) nRangedValue = GetGoldPieceValue(oRightHand); + } + object oRanged = OBJECT_INVALID, oAmmo = OBJECT_INVALID; + // Find the best type of ranged weapon for this player. + if(GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW, oCreature)) + { nBestType1 = BASE_ITEM_LONGBOW; nAmmo = BASE_ITEM_ARROW; nAmmoSlot = INVENTORY_SLOT_ARROWS; sAmmo = "arrow";} + else if(GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW, oCreature)) + { nBestType1 = BASE_ITEM_SHORTBOW; nAmmo = BASE_ITEM_ARROW; nAmmoSlot = INVENTORY_SLOT_ARROWS; sAmmo = "arrow";} + else if(GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, oCreature)) + { nBestType1 = BASE_ITEM_HEAVYCROSSBOW; nAmmo = BASE_ITEM_BOLT; nAmmoSlot = INVENTORY_SLOT_BOLTS; sAmmo = "bolt";} + else if(GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW, oCreature)) + { nBestType1 = BASE_ITEM_LIGHTCROSSBOW; nAmmo = BASE_ITEM_BOLT; nAmmoSlot = INVENTORY_SLOT_BOLTS; sAmmo = "bolt";} + else if(GetHasFeat(FEAT_WEAPON_FOCUS_SLING, oCreature)) + { nBestType1 = BASE_ITEM_SLING; nAmmo = BASE_ITEM_BULLET; nAmmoSlot = INVENTORY_SLOT_BULLETS; sAmmo = "bullet";} + else if(GetHasFeat(FEAT_WEAPON_FOCUS_DART, oCreature)) + { nBestType1 = BASE_ITEM_DART; } + else if(GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN, oCreature)) + { nBestType1 = BASE_ITEM_SHURIKEN; } + else if(GetHasFeat(FEAT_WEAPON_FOCUS_THROWING_AXE, oCreature)) + { nBestType1 = BASE_ITEM_THROWINGAXE; } + // These feats require a bow. + else if(GetHasFeat(FEAT_RAPID_SHOT, oCreature)) + { nBestType1 = BASE_ITEM_LONGBOW; nBestType2 = BASE_ITEM_SHORTBOW; + nAmmo = BASE_ITEM_ARROW; nAmmoSlot = INVENTORY_SLOT_ARROWS; sAmmo = "arrow"; } + // This feat requires a xbow. + else if(GetHasFeat(FEAT_RAPID_RELOAD, oCreature)) + { nBestType1 = BASE_ITEM_HEAVYCROSSBOW; nBestType2 = BASE_ITEM_LIGHTCROSSBOW; + nAmmo = BASE_ITEM_BOLT; nAmmoSlot = INVENTORY_SLOT_BOLTS; sAmmo = "bolt"; } + if(AI_DEBUG) ai_Debug("0i_combat", "3262", "nBestType1: " + IntToString(nBestType1) + " nBestType2: " + IntToString(nBestType2) + + " nAmmo: " + IntToString(nAmmo)); + int nCreatureSize = GetCreatureSize(oCreature) + 1; + // Cycle through the inventory looking for a ranged weapon. + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + nType = GetBaseItemType(oItem); + if(AI_DEBUG) ai_Debug("0i_combat", "3269", "oItem: " + GetName(oItem) + + " Identified: " + IntToString(GetIdentified(oItem)) + + " Ranged Weapon: " + Get2DAString("baseitems", "RangedWeapon", nType)); + // Make sure it is identified and it is a ranged weapon. + if(GetIdentified(oItem) && Get2DAString("baseitems", "RangedWeapon", nType) != "") + { + if(AI_DEBUG) ai_Debug("0i_combat", "3278", " Proficient: " + + IntToString(ai_GetIsProficientWith(oCreature, oItem)) + + " nMaxItemValue: " + IntToString(nMaxItemValue)); + if(ai_GetIsProficientWith(oCreature, oItem)) + { + if(ai_CheckIfCanUseItem(oCreature, oItem)) + { + nItemValue = GetGoldPieceValue(oItem); + if(AI_DEBUG) ai_Debug("0i_combat", "3284", "nItemValue: " + IntToString(nItemValue)); + if(!GetLocalInt(GetModule(), AI_RULE_ILR) || nMaxItemValue >= nItemValue) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3287", " Creature Size: " + IntToString(nCreatureSize) + + " Weapon Size: " + Get2DAString("baseitems", "WeaponSize", nType)); + // Make sure they are large enough to use it. + if(StringToInt(Get2DAString("baseitems", "WeaponSize", nType)) <= nCreatureSize) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3292", "nItemValue: " + IntToString(nItemValue) + + " nRangedValue: " + IntToString(nRangedValue) + " nType: " + IntToString(nType)); + // Is it of the best range weapon type? 0 is any range weapon. + // Also grab any range weapon until we have a best type. + if(nType == nBestType1 || nType == nBestType2 || + nBestType1 == 0 || oRanged == OBJECT_INVALID) + { + if(nItemValue > nRangedValue) + { + if(ai_GetHasItemProperty(oItem, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) + { + oRanged = oItem; nRangedValue = nItemValue; + if(AI_DEBUG) ai_Debug("0i_combat", "3304", "Selecting oRanged: " + GetName(oRanged) + + " nRangedValue: " + IntToString(nRangedValue) + " and doesn't need ammo!"); + } + else + { + if(nBestType1 == 0) + { + if(nType == BASE_ITEM_LONGBOW || nType == BASE_ITEM_SHORTBOW) + { nAmmo = BASE_ITEM_ARROW; sAmmo = "arrow"; nAmmoSlot = INVENTORY_SLOT_ARROWS; } + else if(nType == BASE_ITEM_HEAVYCROSSBOW || nType == BASE_ITEM_LIGHTCROSSBOW) + { nAmmo = BASE_ITEM_BOLT; sAmmo = "bolt"; nAmmoSlot = INVENTORY_SLOT_BOLTS; } + else if(nType == BASE_ITEM_SLING) + { nAmmo = BASE_ITEM_BULLET; sAmmo = "bullet"; nAmmoSlot = INVENTORY_SLOT_BULLETS; } + else nAmmo = 0; + } + // Now do we have ammo for it? + if(AI_DEBUG) ai_Debug("0i_combat", "3320", "nAmmo: " + IntToString(nAmmo)); + if(nAmmo > 0) + { + if(nAmmo == BASE_ITEM_ARROW || + nAmmo == BASE_ITEM_BOLT || + nAmmo == BASE_ITEM_BULLET) oAmmo = GetItemInSlot(nAmmoSlot); + if(oAmmo == OBJECT_INVALID) + { + // We don't have ammo equiped so lets see if we have any in our inventory. + oAmmo = GetFirstItemInInventory(); + while(oAmmo != OBJECT_INVALID) + { + if(GetBaseItemType(oAmmo) == nAmmo) break; + oAmmo = GetNextItemInInventory(); + } + if(oAmmo != OBJECT_INVALID) ActionEquipItem(oAmmo, nAmmoSlot); + } + } + if(oAmmo != OBJECT_INVALID) + { + oRanged = oItem; nRangedValue = nItemValue; + if(AI_DEBUG) ai_Debug("0i_combat", "3307", "Selecting oRanged: " + GetName(oRanged) + + " nRangedValue: " + IntToString(nRangedValue)); + } + } + } + } + } + } + } + } + } + oItem = GetNextItemInInventory(oCreature); + } + // They don't have a range weapon so lets break out. + if(oRanged == OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3357", GetName(oCreature) + " did not equip a ranged weapon!"); + return FALSE; + } + ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND); + return TRUE; +} +int ai_EquipBestMonkMeleeWeapon(object oCreature, object oTarget = OBJECT_INVALID) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "2949", GetName(OBJECT_SELF) + " is equiping best monk melee weapon!"); + int nValue, nRightValue; + int nMaxItemValue = ai_GetMaxItemValueThatCanBeEquiped(GetHitDice(oCreature)); + object oRight = OBJECT_INVALID; + object oRightHand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + if(oRightHand != OBJECT_INVALID) + { + nRightValue = GetGoldPieceValue(oRightHand); + } + // Get the best kama they have in their inventory. + object oItem = GetFirstItemInInventory(oCreature); + // If they don't have any kamas then lets stop, we can't equip a weapon. + if(oItem == OBJECT_INVALID) return FALSE; + while(oItem != OBJECT_INVALID) + { + nValue = GetGoldPieceValue(oItem); + // Make sure they are high enough level to equip this item. + if(nMaxItemValue >= nValue && nValue > 1) + { + // Is it a single handed weapon? + if(GetBaseItemType(oItem) == BASE_ITEM_KAMA) + { + // Replace the lowest value right weapon. + if(nValue > nRightValue) + { + oRight = oItem; nRightValue = nValue; + } + } + } + oItem = GetNextItemInInventory(oCreature); + } + // Finally lets just equip the kama if we have one. + if(oRight == OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "2983", GetName(oCreature) + " did not equip a melee weapon!"); + return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_combat", "2986", GetName(oCreature) + " is equiping " + GetName(oRight) + " in the right hand."); + ActionEquipItem(oRight, INVENTORY_SLOT_RIGHTHAND); + return TRUE; +} +int ai_IsInADangerousAOE(object oCreature, float fMaxRange = AI_RANGE_BATTLEFIELD, int bMove = FALSE) +{ + int bDangerous, nSpell, nCnt = 1; + string sAOEType; + object oAOE = GetNearestObject(OBJECT_TYPE_AREA_OF_EFFECT, oCreature, nCnt); + float fRadius, fDistance = GetDistanceBetween(oCreature, oAOE); + while(oAOE != OBJECT_INVALID && fDistance <= fMaxRange) + { + // AOE's have the tag set to the "LABEL" in vfx_persistent.2da + // I check vs those labels to see if the AOE is offensive. + // Below is the list of Offensive AOE effects. + sAOEType = GetTag(oAOE); + if(sAOEType == "VFX_PER_WEB") { fRadius = 6.7; nSpell = SPELL_WEB; } + else if(sAOEType == "VFX_PER_ENTANGLE") { fRadius = 5.0; nSpell = SPELL_ENTANGLE; } + else if(sAOEType == "VFX_PER_GREASE") { fRadius = 6.0; nSpell = SPELL_GREASE; } + else if(sAOEType == "VFX_PER_EVARDS_BLACK_TENTACLES") + { fRadius = 5.0; nSpell = SPELL_EVARDS_BLACK_TENTACLES; } + //else if(sAOEType == "VFX_PER_DARKNESS") { fRadius = 6.7; nSpell = SPELL_DARKNESS; } + //else if(sAOEType == "VFX_MOB_SILENCE") { fRadius = 4.0; nSpell = SPELL_SILENCE; } + else if(sAOEType == "VFX_PER_FOGSTINK") { fRadius = 6.7; nSpell = SPELL_STINKING_CLOUD; } + else if(sAOEType == "VFX_PER_FOGFIRE") { fRadius = 5.0; nSpell = SPELL_INCENDIARY_CLOUD; } + else if(sAOEType == "VFX_PER_FOGKILL") { fRadius = 5.0; nSpell = SPELL_CLOUDKILL; } + else if(sAOEType == "VFX_PER_FOGMIND") { fRadius = 5.0; nSpell = SPELL_MIND_FOG; } + else if(sAOEType == "VFX_PER_CREEPING_DOOM") { fRadius = 6.7; nSpell = SPELL_CREEPING_DOOM; } + else if(sAOEType == "VFX_PER_FOGACID") { fRadius = 5.0; nSpell = SPELL_ACID_FOG; } + else if(sAOEType == "VFX_PER_FOGBEWILDERMENT") { fRadius = 5.0; nSpell = SPELL_CLOUD_OF_BEWILDERMENT; } + else if(sAOEType == "VFX_PER_WALLFIRE") { fRadius = 10.0; nSpell = SPELL_WALL_OF_FIRE; } + else if(sAOEType == "VFX_PER_WALLBLADE") { fRadius = 10.0; nSpell = SPELL_BLADE_BARRIER; } + else if(sAOEType == "VFX_PER_DELAY_BLAST_FIREBALL") { fRadius = 2.0; nSpell = SPELL_DELAYED_BLAST_FIREBALL; } + else if(sAOEType == "VFX_PER_GLYPH") { fRadius = 2.5; nSpell = SPELL_GLYPH_OF_WARDING; } + else fRadius = 0.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3088", GetName(oCreature) + " distance from AOE is " + FloatToString(fDistance, 0, 2) + + " AOE Radius: " + FloatToString(fRadius, 0, 2) + + " AOE Type: " + GetTag(oAOE)); + // fRadius > 0.0 keeps them from tiggering that they are in a dangerous + // AOE due to having an AOE on them. + if(fRadius > 0.0 && fDistance <= fRadius && + !ai_CreatureImmuneToEffect(GetAreaOfEffectCreator(oAOE), oCreature, nSpell)) + { + bDangerous = TRUE; + if(nSpell == SPELL_WEB || nSpell == SPELL_ENTANGLE) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) bDangerous = FALSE; + if(GetReflexSavingThrow(oCreature) + GetAbilityModifier(ABILITY_DEXTERITY, oCreature) >= ai_GetCharacterLevels(oCreature)) + bDangerous = FALSE; + } + break; + } + oAOE = GetNearestObject(OBJECT_TYPE_AREA_OF_EFFECT, oCreature, ++nCnt); + fDistance = GetDistanceBetween(oCreature, oAOE); + } + if(bDangerous && bMove) + { + location lLocation; + object oTarget; + if(ai_GetIsInCombat(oCreature)) + { + object oMaster = GetMaster(oCreature); + // If we have a ranged weapon then backout and use that. + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + lLocation = GetRandomLocation(GetArea(oCreature), oCreature, fRadius + 1.0); + } + else // we must find a target out of the AOE or fight in the AOE. + { + oTarget = ai_GetNearestTargetNotInAOE(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, TRUE); + if(oTarget != OBJECT_INVALID) lLocation = GetLocation(oTarget); + } + } + else lLocation = GetRandomLocation(GetArea(oCreature), oCreature, fRadius + 1.0); + ai_ClearCreatureActions(); + if(AI_DEBUG) ai_Debug("0i_combat", "3035", GetName(oCreature) + " is moving out of area of effect!"); + ActionMoveToLocation(lLocation, TRUE); + return TRUE; + } + else if(bDangerous) return TRUE; + return FALSE; +} +int ai_GetIsHidden(object oHidden) +{ + int nEffectType; + effect eEffect = GetFirstEffect(oHidden); + while(GetIsEffectValid(eEffect)) + { + nEffectType = GetEffectType(eEffect); + if(nEffectType == EFFECT_TYPE_INVISIBILITY) return 1; + else if(nEffectType == EFFECT_TYPE_IMPROVEDINVISIBILITY) return 1; + else if(nEffectType == EFFECT_TYPE_DARKNESS) return 2; + else if(nEffectType == EFFECT_TYPE_SANCTUARY) return 3; + else if(nEffectType == EFFECT_TYPE_ETHEREAL) return 3; + eEffect = GetNextEffect(oHidden); + } + if(GetActionMode(oHidden, ACTION_MODE_STEALTH)) return 4; + return FALSE; +} +int ai_CastOffensiveSpellVsTarget(object oCaster, object oCreature, int nSpell) +{ + // Check saves. + string sSave = Get2DAString("ai_spells", "SaveType", nSpell); + // There is no save! + if(sSave == "") return TRUE; + // Get the level of the spell. + int nSpellLvl = StringToInt(Get2DAString("spells", "Innate", nSpell)); + // Randomize our check. + nSpellLvl += Random(AI_SPELL_CHECK_DIE) + AI_SPELL_CHECK_BONUS; + // Check feats that might increase our DC. + string sSchool = Get2DAString("spells", "School", nSpell); + if(sSchool == "V") + { + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION, oCaster)) nSpellLvl += 4; + else if(GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION, oCaster)) nSpellLvl += 2; + } + else if(sSchool == "C") + { + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION, oCaster)) nSpellLvl += 4; + else if(GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION, oCaster)) nSpellLvl += 2; + } + else if(sSchool == "N") + { + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY, oCaster)) nSpellLvl += 4; + else if(GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY, oCaster)) nSpellLvl += 2; + } + else if(sSchool == "E") + { + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster)) nSpellLvl += 4; + else if(GetHasFeat(FEAT_SPELL_FOCUS_ENCHANTMENT, oCaster)) nSpellLvl += 2; + } + else if(sSchool == "I") + { + if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION, oCaster)) nSpellLvl += 4; + else if(GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION, oCaster)) nSpellLvl += 2; + } + else if(sSave == "Reflex") + { + string sImmunityType = Get2DAString("ai_spells", "ImmunityType", nSpell); + // Give a bonus to our check for half dmg spells unless they can dodge it! + if((sImmunityType == "Fire" || sImmunityType == "Electricity" || sImmunityType == "Acid" || + sImmunityType == "Cold" || sImmunityType == "Sonic") && + !GetHasFeat(FEAT_IMPROVED_EVASION, oCreature)) nSpellLvl += AI_SPELL_CHECK_NO_EVASION_BONUS; + if(AI_DEBUG) ai_Debug("0i_combat", "3050", " nSpellLvl: " + IntToString(nSpellLvl) + + " > nMagic: " + IntToString(GetReflexSavingThrow(oCreature))); + return (nSpellLvl > GetReflexSavingThrow(oCreature)); + } + else if(sSave == "Fortitude") return (nSpellLvl > GetFortitudeSavingThrow(oCreature)); + else if(sSave == "Will") return (nSpellLvl > GetWillSavingThrow(oCreature)); + return TRUE; +} +int ai_GetDragonDC(object oCreature) +{ + int nDC, nHitDice = GetHitDice(oCreature); + if(nHitDice < 4) { nDC = 12; } + else if(nHitDice < 7) { nDC = 13; } + else if(nHitDice < 10) { nDC = 14; } + else if(nHitDice < 13) { nDC = 16; } + else if(nHitDice < 16) { nDC = 18; } + else if(nHitDice < 19) { nDC = 20; } + else if(nHitDice < 22) { nDC = 22; } + else if(nHitDice < 25) { nDC = 24; } + else if(nHitDice < 28) { nDC = 26; } + else if(nHitDice < 31) { nDC = 28; } + else if(nHitDice < 34) { nDC = 30; } + else if(nHitDice < 37) { nDC = 32; } + else if(nHitDice < 39) { nDC = 34; } + else { nDC = 36; } + string sTag = GetTag(oCreature); + if(sTag == "gold_dragon") nDC += 5; + if(sTag == "red_dragon" || sTag == "silver_dragon") return nDC + 4; + else if(sTag == "black_dragon" || sTag == "brass_dragon") return nDC + 3; + else if(sTag == "green_dragon" || sTag == "copper_dragon") return nDC + 2; + else if(sTag == "blue_dragon" || sTag == "bronze_dragon") return nDC + 1; + //else if(sTag == "white_dragon") nDC += 0; + return nDC; +} +void ai_SetCreatureAIScript(object oCreature) +{ + string sCombatAI = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + // Non-Hostile NPC's do not need to use special tactics by default. + if(sCombatAI == "" && GetLocalInt(GetModule(), AI_RULE_AMBUSH) && d100() < 34) + { + // They should have skill ranks equal to their level + 1 to use a special AI. + int nSkillNeeded = GetHitDice(oCreature) + 1; + /*/ Ambusher: requires either Improved Invisibility or Invisibility. + if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oCreature) || + GetHasSpell(SPELL_INVISIBILITY, oCreature)) + { + int bCast = ai_TryToCastSpell(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature); + if(!bCast) bCast = ai_TryToCastSpell(oCreature, SPELL_INVISIBILITY, oCreature); + if(bCast) sCombatAI = "ai_ambusher"; + } */ + if(GetHasFeat(FEAT_SNEAK_ATTACK, oCreature, TRUE)) + { + sCombatAI = "ai_flanker"; + } + // Ambusher: Requires a Hide and Move silently skill equal to your level + 1. + else if(GetSkillRank(SKILL_HIDE, oCreature) >= nSkillNeeded && + GetSkillRank(SKILL_MOVE_SILENTLY, oCreature) >= nSkillNeeded) + { + sCombatAI = "ai_ambusher"; + } + // Defensive : requires Parry skill equal to your level or Expertise. + else if(GetSkillRank(SKILL_PARRY, oCreature) >= nSkillNeeded || + GetHasFeat(FEAT_EXPERTISE, oCreature) || + GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature)) + { + sCombatAI = "ai_defensive"; + } + else if(GetHasSpell(SPELL_LESSER_DISPEL, oCreature) || + GetHasSpell(SPELL_DISPEL_MAGIC, oCreature) || GetHasSpell(SPELL_GREATER_DISPELLING, oCreature)) + { + sCombatAI = "ai_cntrspell"; + } + else if(ai_CheckClassType(oCreature, AI_CLASS_TYPE_ARCANE) && + ai_GetCharacterLevels(oCreature) > 4) sCombatAI = "ai_ranged"; + else if(ai_EquipBestRangedWeapon(oCreature)) sCombatAI = "ai_ranged"; + else if(GetSkillRank(SKILL_TAUNT, oCreature) >= nSkillNeeded) sCombatAI = "ai_taunter"; + } + if(sCombatAI == "") + { + int nAssociateType = GetAssociateType(oCreature); + if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR) + { + sCombatAI = "ai_default"; + } + else + { + // Select the best ai for this henchmen based on class. + int nClass = GetClassByPosition(1, oCreature); + // If they have more than one class use the default ai. + if(GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID) sCombatAI = "ai_default"; + else if(nClass == CLASS_TYPE_BARBARIAN) sCombatAI = "ai_barbarian"; + else if(nClass == CLASS_TYPE_BARD) sCombatAI = "ai_bard"; + else if(nClass == CLASS_TYPE_CLERIC) sCombatAI = "ai_cleric"; + else if(nClass == CLASS_TYPE_DRUID) sCombatAI = "ai_druid"; + else if(nClass == CLASS_TYPE_FIGHTER) sCombatAI = "ai_fighter"; + else if(nClass == CLASS_TYPE_MONK) sCombatAI = "ai_monk"; + else if(nClass == CLASS_TYPE_PALADIN) sCombatAI = "ai_paladin"; + else if(nClass == CLASS_TYPE_RANGER) sCombatAI = "ai_ranger"; + else if(nClass == CLASS_TYPE_ROGUE) sCombatAI = "ai_rogue"; + else if(nClass == CLASS_TYPE_SORCERER) sCombatAI = "ai_sorcerer"; + else if(nClass == CLASS_TYPE_WIZARD) sCombatAI = "ai_wizard"; + //else if(nClass == CLASS_TYPE_ABERRATION) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_ANIMAL) sCombatAI = "ai_animal"; + //else if(nClass == CLASS_TYPE_CONSTRUCT) sCombatAI = "ai_animal"; + else if(nClass == CLASS_TYPE_DRAGON) sCombatAI = "ai_dragon"; + //else if(nClass == CLASS_TYPE_ELEMENTAL) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_FEY) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_GIANT) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_HUMANOID) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_MAGICAL_BEAST) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_MONSTROUS) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_OOZE) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_OUTSIDER) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_UNDEAD) sCombatAI = "ai_default"; + //else if(nClass == CLASS_TYPE_VERMIN) sCombatAI = "ai_animal"; + else sCombatAI = "ai_default"; + } + } + if(AI_DEBUG) ai_Debug("0i_combat", "3740", GetName(oCreature) + " is setting AI to " + sCombatAI); + SetLocalString(oCreature, AI_DEFAULT_SCRIPT, sCombatAI); + SetLocalString(oCreature, AI_COMBAT_SCRIPT, sCombatAI); +} +int ai_IsImmuneToSneakAttacks(object oCreature, object oTarget) +{ + if(GetHasFeat(FEAT_UNCANNY_DODGE_2, oTarget) && + GetLevelByClass(CLASS_TYPE_ROGUE, oCreature) + 3 < GetLevelByClass(CLASS_TYPE_ROGUE, oTarget)) return TRUE; + if(GetIsImmune(oTarget, IMMUNITY_TYPE_SNEAK_ATTACK)) return TRUE; + object oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTarget); + if(ai_GetHasItemProperty(oSkin, ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS, IP_CONST_IMMUNITYMISC_BACKSTAB)) return TRUE; + return FALSE; +} +int ai_IsStrongerThanMe(object oCreature, int nIndex) +{ + int nEnemyCombat = GetLocalInt(oCreature, AI_ENEMY_COMBAT + IntToString(nIndex)); + int nCreatureCombat = ai_GetMyCombatRating(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "3955", "IsStrongerThanMe: nCreatureCombat: " + + IntToString(nCreatureCombat) + " nEnemyCombat: " + IntToString(nEnemyCombat)); + return (nEnemyCombat > nCreatureCombat); +} +int ai_StrongOpponent(object oCreature, object oTarget, int nAdj = 2) +{ + int nLevel = GetHitDice(oCreature); + if(AI_DEBUG) ai_Debug("0i_combat", "3220", "ai_StrongOpponent"); + nAdj = nAdj *((nAdj + nLevel) / 10); + if(AI_DEBUG) ai_Debug("0i_combat", "3222", "Is the opponent strong? Target CR >= Our level - nAdj(" + + FloatToString(GetChallengeRating(oTarget), 0, 2) + " >= " + IntToString(nLevel - nAdj) + ")"); + return (FloatToInt(GetChallengeRating(oTarget)) >= nLevel - nAdj); +} +int ai_PowerAttackGood(object oCreature, object oTarget, float fAdj) +{ + int nAvgDmg = ai_GetWeaponDamage(oCreature, 2); + if(AI_DEBUG) ai_Debug("0i_combat", "3412", "PowerAttack: (nAvgDmg: " + IntToString(nAvgDmg) + + " > Target HP: " + IntToString(GetCurrentHitPoints(oTarget)) + + ") Skip: " + IntToString(nAvgDmg > GetCurrentHitPoints(oTarget))); + if(nAvgDmg > GetCurrentHitPoints(oTarget)) return FALSE; + float fAvgDmg = IntToFloat(nAvgDmg); + float fTargetAC = IntToFloat(GetAC(oTarget)); + float fCreatureAtk = IntToFloat(ai_GetCreatureAttackBonus(oCreature)); + float fNormalChance = (21.0 - (fTargetAC - fCreatureAtk)) / 20.0; + // Our chance to hit is already minimum of 5% so this doesn't hurt our chance! + if(fNormalChance <= 0.05) return TRUE; + float fAdjDamage = (fAvgDmg + fAdj) * ((21.0-(fTargetAC - fCreatureAtk + fAdj))/20); + if(AI_DEBUG) ai_Debug("0i_combat", "3420", "fNormalDamage: " + FloatToString(fNormalChance * fAvgDmg, 0, 2) + + " < fAdjDamage: " + FloatToString(fAdjDamage, 0, 2) + " = " + IntToString(fNormalChance * fAvgDmg < fAdjDamage)); + return fNormalChance * fAvgDmg < fAdjDamage; +} +int ai_AttackPenaltyOk(object oCreature, object oTarget, float fAtkAdj) +{ + float fTargetAC = IntToFloat(GetAC(oTarget)); + float fCreatureAtk = IntToFloat(ai_GetCreatureAttackBonus(oCreature)); + float fNormalChance = (21.0-(fTargetAC - fCreatureAtk))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3431", "Normal Avg Chance: " + FloatToString(fNormalChance, 0, 2) + " <= 0.05"); + // We already need a 20 to hit so this doesn't hurt our chances! + if(fNormalChance <= 0.05) return TRUE; + float fAdjChance = (21.0-(fTargetAC - fCreatureAtk + fAtkAdj))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3435", "Adjusted Avg Chance: " + FloatToString(fAdjChance, 0, 2) + " > 0.55"); + // if our chance is 55% or better to hit then use it. + return fAdjChance > 0.55; +} +int ai_AttackBonusGood(object oCreature, object oTarget, float fAtkAdj) +{ + float fTargetAC = IntToFloat(GetAC(oTarget)); + float fCreatureAtk = IntToFloat(ai_GetCreatureAttackBonus(oCreature)); + float fNormalChance = (21.0-(fTargetAC - fCreatureAtk))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3450", "Normal Avg Chance: " + FloatToString(fNormalChance, 0, 2) + " > 0.99"); + // We already hit them with any roll so this will not help. + if(fNormalChance > 0.99) return FALSE; + float fAdjChance = (21.0-(fTargetAC - fCreatureAtk - fAtkAdj))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3454", "Adjusted Avg Chance: " + FloatToString(fAdjChance, 0, 2) + " < 0.0"); + // if our chance increases our to hit then this is good. + return fAdjChance > 0.0; +} +int ai_ACAdjustmentGood(object oCreature, object oTarget, float fACAdj) +{ + float fCreatureAC = IntToFloat(GetAC(oCreature)); + float fTargetAtk = IntToFloat(ai_GetCreatureAttackBonus(oTarget)); + float fNormalChance = (21.0-(fCreatureAC - fTargetAtk))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3444", "Normal Chance To Hit: " + FloatToString(fNormalChance, 0, 2) + " <= 0.05"); + // They already need a 20 to hit so adding more AC is worthless. + if(fNormalChance <= 0.05) return FALSE; + float fAdjChance = (21.0-(fCreatureAC - fTargetAtk + fACAdj))/20.0; + if(AI_DEBUG) ai_Debug("0i_combat", "3448", "Adjusted Chance To Hit: " + FloatToString(fAdjChance, 0, 2) + " < 1.00"); + // Anything less than 1 helps are AC! + return fAdjChance < 1.00; +} +int ai_CanIMoveInCombat(object oCreature) +{ + // DC 15 tumble check is required to not give attacks of opportunity. + return (GetHasFeat(FEAT_MOBILITY, oCreature) || GetHasFeat(FEAT_SPRING_ATTACK, oCreature) || + GetSkillRank(SKILL_TUMBLE, oCreature) > 9); +} +int ai_CanIUseRangedWeapon(object oCreature, int nInMelee) +{ + return (!nInMelee || ai_GetEnemyAttackingMe(oCreature) == OBJECT_INVALID); +} +int ai_CheckRangedCombatPosition(object oCreature, object oTarget, int nAction) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "3559", "Ranged attack: See oTarget? " + + IntToString(GetObjectSeen(oTarget, oCreature)) + " Line of Sight? " + + IntToString(LineOfSightObject(oCreature, oTarget))); + if(nAction == AI_LAST_ACTION_RANGED_ATK) + { + // Watch the nearest enemy instead of our target as they could move toward us. + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + float fDistance = GetDistanceBetween(oCreature, oNearestEnemy); + if(AI_DEBUG) ai_Debug("0i_combat", "3337", "oNearestEnemy: " + GetName(oNearestEnemy) + + " fDistance: " + FloatToString(fDistance, 0, 2)); + // If we have sneak attack then we want to be within 30'. + if(GetHasFeat(FEAT_SNEAK_ATTACK, oCreature)) + { + if(fDistance > AI_RANGE_CLOSE) + { + // We check this because if the enemy is moving or has not + // started acting then we don't want to move up on them as they + // might move towards us. Just attack! Only sneak attack if they are busy. + int nAction = GetCurrentAction(oNearestEnemy); + if(AI_DEBUG) ai_Debug("0i_combat", "3353", GetName(oNearestEnemy) + " current action: " + IntToString(nAction)); + if(nAction == ACTION_MOVETOPOINT || + nAction == ACTION_INVALID || + nAction == ACTION_RANDOMWALK) return FALSE; + // If they are attacking make sure it is in melee? + // If not then don't move since they might be moving toward us. + if(nAction == ACTION_ATTACKOBJECT) + { + if(!ai_GetNumOfEnemiesInRange(oNearestEnemy)) return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_combat", "3355", GetName(oCreature) + " is moving closer [8.0] to " + + GetName(oNearestEnemy) + " to sneak attack with a ranged weapon."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + ActionMoveToObject(oNearestEnemy, TRUE, AI_RANGE_CLOSE); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + } + else if(fDistance < AI_RANGE_LONG) + { + // Lets move back a little, too far and we miss attacks! + if(AI_DEBUG) ai_Debug("0i_combat", "3374", GetName(oCreature) + " is moving away from " + + GetName(oNearestEnemy) + "[2.0] to use a ranged weapon."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + ActionMoveAwayFromObject(oNearestEnemy, TRUE, 2.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + } + // If we are casting a hostile spell then check positioning. + else if(nAction > -1 && Get2DAString("ai_spells", "HostileSetting", nAction) == "1") + { + // We are out of melee and casting a spell on an ally so don't move. + if(GetReputation(oCreature, oTarget) > 89) return FALSE; + float fSpellRange = ai_GetSpellRange(nAction); + float fTargetRange = GetDistanceBetween(oCreature, oTarget); + if(AI_DEBUG) ai_Debug("0i_combat", "3389", "fSpellRange: " + FloatToString(fSpellRange, 0, 2) + + " fTargetRange: " + FloatToString(fTargetRange, 0, 2)); + // Adjust the ranges to see if we are too close. + if(fSpellRange == 5.0) fSpellRange = 4.5f; + //else if(fSpellRange == 8.0) fSpellRange = 8.0f; + else if(fSpellRange > 10.0f) fSpellRange = 10.0f; + if(AI_DEBUG) ai_Debug("0i_combat", "3395", "Adjusted spell range is " + + FloatToString(fSpellRange, 0, 2) + " : " + GetName(oTarget) + " range is " + + FloatToString(fTargetRange, 0, 2) + "."); + // We are closer than we have to be to cast our spell. + if(fTargetRange < fSpellRange) + { + // Lets move back a little, too far and we miss attacks! + if(AI_DEBUG) ai_Debug("0i_combat", "3402", GetName(oCreature) + " is moving away from " + + GetName(oTarget) + "[2.0] to cast a spell."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + ActionMoveAwayFromObject(oTarget, FALSE, 2.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } +} + return FALSE; +} +int ai_CheckMeleeCombatPosition(object oCreature, object oTarget, int nAction, int nBaseItemType = 0) +{ + // If we are not being attacked then we might want to back out of combat. + if(ai_GetEnemyAttackingMe(oCreature) != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3417", "I am being attacked so stand my ground!"); + return FALSE; + } + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + float fDistance = GetDistanceBetween(oCreature, oNearestEnemy); + if(AI_DEBUG) ai_Debug("0i_combat", "3422", "oNearestEnemy: " + GetName(oNearestEnemy) + " fDistance " + FloatToString(fDistance, 0, 2)); + if(nAction == AI_LAST_ACTION_RANGED_ATK) + { + if(AI_DEBUG) ai_Debug("0i_combat", "3425", GetName(oCreature) + " is moving away from " + GetName(oNearestEnemy) + + "[" + FloatToString(AI_RANGE_MELEE - fDistance + 1.0, 0, 2) + "]" + " to use a ranged weapon."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + // Lets move just out of melee range! + int bRun = ai_CanIMoveInCombat(oCreature); + ActionMoveAwayFromObject(oNearestEnemy, bRun, AI_RANGE_MELEE - fDistance + 1.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + // If we want to cast a spell this round then back away! + else if(nAction > -1) + { + // Some items we don't need to move on such as wands, staves, and rods. + if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == BASE_ITEM_MAGICSTAFF || + nBaseItemType == BASE_ITEM_MAGICROD) return FALSE; + float fSpellRange = ai_GetSpellRange(nAction); + // A Touch spell means we should not move if we are not the target. + if(fSpellRange <= 5.0 && oCreature != oTarget) return FALSE; + if(AI_DEBUG) ai_Debug("0i_combat", "3446", GetName(oCreature) + " is moving away from " + + GetName(oTarget) + "[" + FloatToString(AI_RANGE_MELEE - fDistance + 1.0, 0, 2) + "] to cast a spell."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + SetActionMode(oCreature, ACTION_MODE_DEFENSIVE_CAST, FALSE); + // Lets move just out of melee range! + int bRun = ai_CanIMoveInCombat(oCreature); + ActionMoveAwayFromObject(oNearestEnemy, bRun, AI_RANGE_MELEE - fDistance + 1.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return TRUE; + } + return FALSE; +} +int ai_CheckCombatPosition(object oCreature, object oTarget, int nInMelee, int nAction, int nBaseItemType = 0) +{ + if(AI_DEBUG) ai_Debug("0i_combat", "3460", "|-----> Checking position in combat: " + + GetName(oCreature) + " nMelee: " + IntToString(nInMelee) + + " Action: " + IntToString(nAction) + + " Hold mode: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) + + " Use Advanced Movement: " + IntToString(GetLocalInt(GetModule(), AI_RULE_ADVANCED_MOVEMENT))); + // We don't want to move around in combat if we were told to hold. + if(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) return FALSE; + if(!GetLocalInt(GetModule(), AI_RULE_ADVANCED_MOVEMENT)) return FALSE; + if(ai_CompareLastAction(oCreature, AI_LAST_ACTION_MOVE)) return FALSE; + // We are not in melee combat so lets see how close we should get. + if(!nInMelee) return ai_CheckRangedCombatPosition(oCreature, oTarget, nAction); + // If we are in melee we might need to move out of combat. + return ai_CheckMeleeCombatPosition(oCreature, oTarget, nAction, nBaseItemType); +} diff --git a/src/module/nss/0i_constants.nss b/src/module/nss/0i_constants.nss new file mode 100644 index 0000000..5413ac4 --- /dev/null +++ b/src/module/nss/0i_constants.nss @@ -0,0 +1,667 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Name: 0i_constants +// Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Include script for handling all constants for the ai. + These constants are static and can only be changed in the toolset. + Changes to any constants will not take effect until the scripts are recompiled. +*/////////////////////////////////////////////////////////////////////////////// + +const string PHILOS_VERSION = "Philos' Enhancing Player System (PEPS) version:07.12.25"; +// The following constants are designed to be changed to allow the AI to work +// differently based on what a developer wants. +// If you change these constants make sure the database has been removed +// so the ai_SetAIRules() will rewrite the new server rule values. +// File Name: peps_database.sqlite3 +//********************************** SERVER *********************************** +// Turn On/Off Debug. You can only use the debug with the pi_debug/pe_debug scripts. +// This will only work if you are using the PEPS menu system. +const int AI_DEBUG = FALSE; +// Defines if we are compiling for single player or a server. Always on for servers! +const int AI_SERVER = FALSE; +// The number of classes allowed for a creature to take in the server/module. +const int AI_MAX_CLASSES_PER_CHARACTER = 8; +// Taunts cool down time before the AI attemps another Taunt. +const int AI_TAUNT_COOLDOWN = 3; +// Animal Empathy cool down time before the AI attemps another check. +const int AI_EMPATHY_COOLDOWN = 3; +// Arcane Spell failure% or less than, for a caster to still try to cast a spell. +const int AI_ASF_WILL_USE = 15; +// Monsters chance to heal while in combat per round. +const int AI_MONSTER_HEAL_IN_COMBAT_CHANCE = 70; +// Monsters chance to heal when out of combat per heart beat. +const int AI_MONSTER_HEAL_OUT_COMBAT_CHANCE = 70; +// Allows Henchman to have a widget if using the henchman AI. +const int AI_HENCHMAN_WIDGET = TRUE; +// Change the Custom token number if it conflicts with your server. +const int AI_BASE_CUSTOM_TOKEN = 1000; +// Delay between creatures casting Buff spells. Must be minimum of 0.1 seconds. +const float AI_HENCHMAN_BUFF_DELAY = 0.2; + +//******************* These can be changed within the game ******************* +// Moral checks on or off. If wounded they will make Will saves, if they fail the flee. +const int AI_MORAL_CHECKS = FALSE; +// Allows monsters to prebuff before combat starts. +const int AI_PREBUFF = TRUE; +// Allows monsters cast summons spells when prebuffing. +const int AI_PRESUMMONS = TRUE; +// Allows monsters to use tactical AI scripts such as ambush, flanker, ranged. +const int AI_TACTICAL = TRUE; +// Enemies may summon familiars and Animal companions and will be randomized. +const int AI_SUMMON_COMPANIONS = FALSE; +// Allow the AI to move during combat base on the situation and action taking. +const int AI_ADVANCED_MOVEMENT = TRUE; +// Follow Item Level Restrictions for AI. +const int AI_ITEM_LEVEL_RESTRICTIONS = FALSE; +// Allow the AI to use Use Magic Device. +const int AI_USE_MAGIC_DEVICE = TRUE; +// Allow the AI to use healing kits. +const int AI_HEALING_KITS = TRUE; +// Associates are permanent and don't get removed when the master dies. +const int AI_COMPANIONS_PERMANENT = FALSE; +// Monster AI's chance (0 to 100) to attack the weakest target instead of the nearest. +// The higher the number the harder the encounter with monsters! +const int AI_TARGET_WEAKEST = 0; +// Variable that can change the distance creatures will come and attack after +// hearing a shout from an ally that sees or hears an enemy. +// Or when searching for an invisible, heard enemy. +// 10.0 Short, 30.0 Average, 40.0 Long, 60.0 Huge. +const float AI_SEARCH_DISTANCE = 30.0; +// Enemy corpses remain on the floor instead of dissappearing. +const int AI_CORPSE_REMAIN = FALSE; +// Monsters will wander around when not in combat. +const int AI_WANDER = FALSE; +// Variable distance monsters can wander away from their spawn point. +const float AI_WANDER_DISTANCE = 0.0; +// Variable that allows monsters to open doors when wandering around out of combat. +const int AI_OPEN_DOORS = FALSE; +// Monster's actual perception distance. +// 8 Short(10 sight/listen) 9 Medium(20 sight/listen) 10 Long(35 sight/20 listen) +// 11 Default(Based on appearance.2da Most creatures use 9, bosses use 10). +const int AI_MONSTER_PERCEPTION = 11; +// Should the AI auto adjust the XP scale to remove party size penalty? +const int AI_PARTY_SCALE = FALSE; + +//**************************** DM Based Constants **************************** +// The constant the server wants set to allow players to use specific widgets buttons. +// 0 Allows all buttons. See ASSOCIATE_WIDGET_BUTTONS below for values needed to be +// added to block those buttons. +// Example: BTN_CMD_GHOST_MODE = 0x00000800; To remove you would put 2048 below. +// Since Hex 800 is Decimal 2048. +const int AI_DM_WIDGET_ACCESS_BUTTONS = 0; +// The constant the server wants set to allow players to use specific AI buttons. +// 0 Allows all buttons. See ASSOCIATE_AI_BUTTONS below for values needed to be +// added to block those buttons. +// Example: BTN_AI_MAGIC_LEVEL = 0x00000040; To remove you would put 64 below. +// Since Hex 40 is Decimal 64. Adding BTN_AI_LOOT = 0x00001000; to that would be +// 64 + 4096 = 4160 to Block Magic Level and Auto Looting. +const int AI_DM_AI_ACCESS_BUTTONS = 0; +//************************** CONVERSATION CONSTANTS ************************** +// Player's can tell their associates to ignore enemy associates. +const int AI_IGNORE_ASSOCIATES_ON = TRUE; +// Associates with a Taunt skill higher than their level can be told to taunt. +const int AI_TAUNTING_ON = TRUE; +// Associates that cast spells can be told to use counterspell. +const int AI_COUNTERSPELLING_ON = TRUE; +// Associates with lore skill higher than the master can identify items. +const int AI_IDENTIFY_ON = TRUE; +// Associates can be called upon to scout ahead for monsters. +const int AI_SCOUT_AHEAD_ON = TRUE; +// A player can open a henchmen's inventory. +const int AI_OPEN_INVENTORY = TRUE; +// Allows players to have associates pickup loot. +const int AI_PICKUP_LOOT = TRUE; +// Allows players to remove a henchman. +const int AI_REMOVE_HENCHMAN_ON = FALSE; +//***************************** Health Constants ***************************** +// % of health for when a creature is considered wounded. +const int AI_HEALTH_WOUNDED = 50; +// % of health when creature is considered badly wounded. +const int AI_HEALTH_BLOODY = 25; +//***************************** MORAL CONSTANTS ****************************** +// Moral checks are only made once a creature is below AI_HEALTH_WOUNDED. +// The moral DC is AI_MORAL_DC - the number of Allies. Default: 5 +const int AI_WOUNDED_MORAL_DC = 5; +// Once a creature goes below AI_HEALTHY_BLOODY then it uses this moral DC. Default: 15 +const int AI_BLOODY_MORAL_DC = 15; +//******************************* WINDOW CONSTANTS ***************************** +const string AI_MAIN_NUI = "ai_main_nui"; +const string AI_COMMAND_NUI = "_command_nui"; +const string AI_NUI = "_ai_nui"; +const string AI_WIDGET_NUI = "_widget_nui"; +const string AI_LOOTFILTER_NUI = "_lootfilter_nui"; +const string AI_COPY_NUI = "_copy_nui"; +const string AI_PLUGIN_NUI = "ai_plugin_nui"; +const string AI_QUICK_WIDGET_NUI = "_quick_widget_nui"; +const string AI_SPELL_MEMORIZE_NUI = "_spell_memorize_nui"; +const string AI_SPELL_KNOWN_NUI = "_spell_known_nui"; +const string AI_SPELL_DESCRIPTION_NUI = "ai_spell_desc_nui"; +const string AI_EFFECT_ICON_NUI = "ai_effect_icon_nui"; +//******************************* CORE CONSTANTS ******************************* +// The following constants are core constants and changing any of these without +// understanding the whole system could cause unforseen results. +// CHANGE AT YOUR OWN RISK. +// Variable used to asave a monster object for changing. +const string AI_MONSTER_OBJECT = "AI_MONSTER_OBJECT"; +// Variable used to save a monsters json for changing. +const string AI_MONSTER_JSON = "AI_MONSTER_JSON"; +// Variable used to let PEPS know that a monster plugin changed the monster. +const string AI_MONSTER_CHANGED = "AI_MONSTER_CHANGED"; +// Variable used to save an associates class list to change known list json. +const string AI_CLASS_LIST_JSON = "AI_CLASS_LIST_JSON"; +// Startup variable to tell plugins that we have started. +const string AI_STARTING_UP = "AI_STARTING_UP"; +// Add plugin variable to tell plugins that we are adding them to PEPS. +const string AI_ADD_PLUGIN = "AI_ADD_PLUGIN"; +// Startup variable to tell plugins what json array to add their plugin to. +const string AI_JSON_PLUGINS = "AI_JSON_PLUGINS"; +// Plugin variable to have plugins return if they setup the plugin in the json for PEPS. +const string AI_PLUGIN_SET = "AI_PLUGIN_SET"; +// Monster modification variable to let PEPS know what mods are available. +const string AI_MONSTER_MOD_JSON = "AI_MONSTER_MOD_JSON"; +// The maximum number of henchman the code works with. +const int AI_MAX_HENCHMAN = 12; +// Delay between Henchman casting Healing spells. Must be minimum of 0.5 seconds. +const float AI_HENCHMAN_HEALING_DELAY = 6.0; +// A variable that can be set on creatures to stop mobile animations. +const string AI_NO_ANIMATION = "AI_NO_ANIMATION"; +// How many seconds in a combat round. +const int AI_COMBAT_ROUND_IN_SECONDS = 6; +// Used for actions that take x seconds but don't have an action constant. +const string AI_COMBAT_WAIT_IN_SECONDS = "AI_COMBAT_WAIT_IN_SECONDS"; +// Constants used to define the difficulty of the battle for associates. +// 20+ : Impossible - Cannot win. +// 17 to 19 : Overpowering - Use all of our powers. +// 15 to 16 : Very Difficult - Use all of our power (Highest level spells). +// 11 to 14 : Challenging - Use most of our power (Higher level powers). +// 8 to 10 : Moderate - Use half of our power (Mid level powers and less). +// 5 to 7 : Easy - Use our weaker powers (Lowest level powers). +// 2 to 4 : Effortless - Don't waste spells and powers on this. +// 1 or less: Pointless - We probably should ignore these dangers. +const int AI_COMBAT_IMPOSSIBLE = 21; +const int AI_COMBAT_OVERPOWERING = 17; +const int AI_COMBAT_VERY_DIFFICULT = 15; +const int AI_COMBAT_CHALLENGING = 11; +const int AI_COMBAT_MODERATE = 10; +const int AI_COMBAT_EASY = 7; +const int AI_COMBAT_EFFORTLESS = 4; +// Variables used to keep track of enemies in combat. +const string AI_ENEMY = "AI_ENEMY"; // The enemy objects. +const string AI_ENEMY_DISABLED = "AI_ENEMY_DISABLED"; // Int if they are disabled. +const string AI_ENEMY_PERCEIVED = "AI_ENEMY_PERCEIVED"; // TRUE if we have seen or heard them, FALSE if not. +const string AI_ENEMY_RANGE = "AI_ENEMY_RANGE"; // The range from OBJECT_SELF. +const string AI_ENEMY_COMBAT = "AI_ENEMY_COMBAT"; // Combat rating: (BAB + AC - 10) / 2 +const string AI_ENEMY_MELEE = "AI_ENEMY_MELEE"; // Enemies within 5 meters - Allies within 5 meters. +const string AI_ENEMY_HEALTH = "AI_ENEMY_HEALTH"; // % of hitpoints. +const string AI_ENEMY_NUMBERS = "AI_ENEMY_NUM"; // Number of enemies in combat. +const string AI_ENEMY_POWER = "AI_ENEMY_POWER"; // (Level * Health %) / 100 added for each enemy to this. +const string AI_ENEMY_NEAREST = "AI_ENEMY_NEAREST"; // Nearest enemy to OBJECT_SELF. +// Variables used to keep track of allies in combat. +const string AI_ALLY = "AI_ALLY"; // All friendly creatures +const string AI_ALLY_DISABLED = "AI_ALLY_DISABLED"; // Int if they are disabled. +const string AI_ALLY_PERCEIVED = "AI_ALLY_PERCEIVED"; // All allies are set to be seen and heard. +const string AI_ALLY_RANGE = "AI_ALLY_RANGE"; // The range from OBJECT_SELF. +const string AI_ALLY_COMBAT = "AI_ALLY_COMBAT"; // Combat rating: (BAB + AC - 10) / 2 +const string AI_ALLY_MELEE = "AI_ALLY_MELEE"; // Enemies within 5 meters - Allies within 5 meters. +const string AI_ALLY_HEALTH = "AI_ALLY_HEALTH"; // % of hitpoints. +const string AI_ALLY_NUMBERS = "AI_ALLY_NUM"; // Number of allies in combat. +const string AI_ALLY_POWER = "AI_ALLY_POWER"; // (Level * Health %) / 100 added for each enemy to this. +// Variable name used to define the ai scripts being used by creatures. +const string AI_DEFAULT_SCRIPT = "AI_DEFAULT_SCRIPT"; +const string AI_COMBAT_SCRIPT = "AI_COMBAT_SCRIPT"; +// Constants used in a creatures listening patterns. +const string AI_I_SEE_AN_ENEMY = "AI_I_SEE_AN_ENEMY"; +const string AI_I_HEARD_AN_ENEMY = "AI_I_HEARD_AN_ENEMY"; +const string AI_ATKED_BY_WEAPON = "AI_ATK_BY_WEAPON"; +const string AI_ATKED_BY_SPELL = "AI_ATK_BY_SPELL"; +const string AI_I_AM_WOUNDED = "AI_I_AM_WOUNDED"; +const string AI_I_AM_DEAD = "AI_I_AM_DEAD"; +const string AI_I_AM_DISEASED = "AI_I_AM_DISEASED"; +const string AI_I_AM_POISONED = "AI_I_AM_POISONED"; +const string AI_I_AM_WEAK = "AI_I_AM_WEAK"; +const int AI_ALLY_SEES_AN_ENEMY = 1; +const int AI_ALLY_HEARD_AN_ENEMY = 2; +const int AI_ALLY_ATKED_BY_WEAPON = 3; +const int AI_ALLY_ATKED_BY_SPELL = 4; +const int AI_ALLY_IS_WOUNDED = 5; +const int AI_ALLY_IS_DEAD = 6; +const int AI_ALLY_IS_DISEASED = 7; +const int AI_ALLY_IS_POISONED = 8; +const int AI_ALLY_IS_WEAK = 9; +const string AI_MY_TARGET = "AI_MY_TARGET"; +// Constant used by monsters to reduce checks while searching for unseen targets. +const string AI_AM_I_SEARCHING = "AI_AM_I_SEARCHING"; +// Used to keep track of oCreature attempting to hide. +const string AI_TRIED_TO_HIDE = "AI_TRIED_TO_HIDE"; +// Constant used by creatures to keep track of invisible creatures. +const string AI_IS_INVISIBLE = "AI_IS_INVISIBLE"; +// Constants used in combat to keep track of a creatures last action. +// 0+ is the last spell cast from the line number in Spells.2da. +const string sLastActionVarname = "AI_LAST_ACTION"; +const int AI_LAST_ACTION_CAST_SPELL = -1; +const int AI_LAST_ACTION_NONE = -2; +const int AI_LAST_ACTION_MELEE_ATK = -3; +const int AI_LAST_ACTION_RANGED_ATK = -4; +const int AI_LAST_ACTION_USED_FEAT = -5; +const int AI_LAST_ACTION_USED_ITEM = -6; +const int AI_LAST_ACTION_USED_SKILL = -7; +const int AI_LAST_ACTION_MOVE = -8; +// Variable name used to keep track of Action Modes. +const string AI_CURRENT_ACTION_MODE = "AI_CURRENT_ACTION_MODE"; +// Variable name used to keep track of object usage by the AI. +const string AI_OBJECT_IN_USE = "AI_OBJECT_IN_USE"; +// Variable name used to keep a creatures attacked targets. +const string AI_ATTACKED_PHYSICAL = "AI_ATTACKED_PHYSICAL"; +const string AI_ATTACKED_SPELL = "AI_ATTACKED_SPELL"; +// Variable name used to keep track of a creatures normal polymorph form. +const string AI_NORMAL_FORM = "AI_NORMAL_FORM"; +// Variable name used to keep track if a creature has been buffed yet. +const string AI_CASTER_BUFFS_SET = "AI_CASTER_BUFFS_SET"; +// Variable name used to keep track of rounds in combat for a custom ai script. +const string AI_ROUND = "AI_ROUND"; +// Combat Ranges +const float AI_RANGE_MELEE = 5.0f; // Anyone within this is considered to be in melee. +const float AI_RANGE_CLOSE = 8.0f; // For anything requiring to be within 30'. +const float AI_RANGE_LONG = 15.0f; // Mainly used for distance ranged attacks. +const float AI_RANGE_PERCEPTION = 35.0f; // This is the distance for perception in battle. +const float AI_RANGE_BATTLEFIELD = 40.0f; // This is the size of the battlefield area. +// Spell ranges. +const float AI_SHORT_DISTANCE = 8.0f; +const float AI_MEDIUM_DISTANCE = 20.0f; +const float AI_LONG_DISTANCE = 40.0f; +// When computer checks if a creature should cast a specific spell at a target. +// Computer makes a spell check vs the targets saving throw. +// Spell check roll for the caster is +// [Innate spell Level + Random (AI_SPELL_CHECK_DIE) + AI_SPELL_CHECK_BONUS] +// If the spell gives a save for half (i.e. FireBall) and the target does not have +// Evasion then they get an additional bonus of AI_SPELL_CHECK_NO_EVASION_BONUS. +const int AI_SPELL_CHECK_DIE = 6; +const int AI_SPELL_CHECK_BONUS = 3; +const int AI_SPELL_CHECK_NO_EVASION_BONUS = 10; +// When the computer checks if a creature should use defensive casting it looks +// at the spell level + AI_DEFENSIVE_CASTING_DC vs casters concentration +// and feat bonuses (i.e. COMBAT_CASTING) + Random (AI_DEFENSIVE_CASTING_ROLL). +const int AI_DEFENSIVE_CASTING_DC = 19; // 19 will allow them to use it at 50% effectiveness. +const int AI_DEFENSIVE_CASTING_DIE = 10; +// When the computer checks to see if it should cast in melee combat it looks +// at CASTING_IN_MELEE_DC + SpellLevel + (Num of creatures in melee * GetHitDice (NearestEnemy)); +// vs the casters concentration + Random (AI_CASTING_IN_MELEE_ROLL). +const int AI_CASTING_IN_MELEE_DC = 10; +const int AI_CASTING_IN_MELEE_ROLL = 10; +// For getting a specific class the following constants were added to flesh out +// the CLASS_TYPE_* +const int AI_CLASS_TYPE_CASTER = -1; +const int AI_CLASS_TYPE_DIVINE = -2; +const int AI_CLASS_TYPE_ARCANE = -3; +const int AI_CLASS_TYPE_WARRIOR = -4; +// For getting a specific race the following constants were added to flesh out +// the RACIAL_TYPE_* +const int AI_RACIAL_TYPE_ANIMAL_BEAST = -1; +const int AI_RACIAL_TYPE_HUMANOID = -2; +// Bitwise constants for negative conditions we might want to try to cure +const int AI_CONDITION_POISON = 0x00000001; +const int AI_CONDITION_DISEASE = 0x00000002; +const int AI_CONDITION_BLINDDEAF = 0x00000004; +const int AI_CONDITION_ATK_DECREASE = 0x00000008; +const int AI_CONDITION_DMG_DECREASE = 0x00000010; +const int AI_CONDITION_DMG_I_DECREASE = 0x00000020; +const int AI_CONDITION_SKILL_DECREASE = 0x00000040; +const int AI_CONDITION_SAVE_DECREASE = 0x00000080; +const int AI_CONDITION_SR_DECREASE = 0x00000100; +const int AI_CONDITION_AC_DECREASE = 0x00000200; +const int AI_CONDITION_SLOW = 0x00000400; +const int AI_CONDITION_ABILITY_DRAIN = 0x00000800; +const int AI_CONDITION_LEVEL_DRAIN = 0x00001000; +const int AI_CONDITION_CHARMED = 0x00002000; +const int AI_CONDITION_DAZED = 0x00004000; +const int AI_CONDITION_STUNNED = 0x00008000; +const int AI_CONDITION_FRIGHTENED = 0x00010000; +const int AI_CONDITION_CONFUSED = 0x00020000; +const int AI_CONDITION_CURSE = 0x00040000; +const int AI_CONDITION_PARALYZE = 0x00080000; +const int AI_CONDITION_DOMINATED = 0x00100000; +// Database constants for Associate modes. +const string AI_MODE_DB_TABLE = "AI_MODE_DB_TABLE"; +// Bitwise constants for Associate modes that are used with Get/SetAssociateMode(). +const string sAIModeVarname = "ASSOCIATE_MODES"; +//const int AI_MODE_DISTANCE_CLOSE = 0x00000001; // Stays within AI_DISTANCE_CLOSE of master. +//const int AI_MODE_DISTANCE_MEDIUM = 0x00000002; // Stays within AI_DISTANCE_MEDIUM of master. +const int AI_MODE_ACTION_GHOST = 0x00000004; // Defines if the player is using Ghost mode when using associate actions. +const int AI_MODE_SELF_HEALING_OFF = 0x00000008; // Creature will not use healing items or spells on self. +const int AI_MODE_PARTY_HEALING_OFF = 0x00000010; // Creature will not use healing items or spells on party. +const int AI_MODE_GHOST = 0x00000020; // Creature can move through other creatures. +const int AI_MODE_OPEN_DOORS = 0x00000040; // Creature will attempted to open all doors. +const int AI_MODE_EQUIP_WEAPON_OFF = 0x00000080; // The AI will not equip weapons. +const int AI_MODE_BASH_LOCKS = 0x00000100; // Will bash locks if cannot open door/placeable. +const int AI_MODE_AGGRESSIVE_SEARCH = 0x00000200; // Sets associate to continuous search mode. +const int AI_MODE_AGGRESSIVE_STEALTH = 0x00000400; // Sets associate to continuous stealth mode. +const int AI_MODE_PICK_LOCKS = 0x00000800; // Will pick locks if possible. +const int AI_MODE_DISARM_TRAPS = 0x00001000; // Will disarm traps. +const int AI_MODE_SCOUT_AHEAD = 0x00002000; // Will move ahead of master and scout. +const int AI_MODE_DEFEND_MASTER = 0x00004000; // Will attack enemies attacking our master. +const int AI_MODE_STAND_GROUND = 0x00008000; // Will stay in one place until new command. +const int AI_MODE_STOP_RANGED = 0x00010000; // Will not use ranged weapons. +const int AI_MODE_FOLLOW = 0x00020000; // Keeps associate following master ignoring combat. +const int AI_MODE_PICKUP_ITEMS = 0x00040000; // Will pickup up all items for master. +const int AI_MODE_COMMANDED = 0x00080000; // In Command mode then don't follow, search, etc. +const int AI_MODE_IGNORE_TRAPS = 0x00100000; // Creature will ignore traps on the floor. +const int AI_MODE_NO_STEALTH = 0x00200000; // Will not cast invisibilty or use stealth. +const int AI_MODE_DO_NOT_SPEAK = 0x00400000; // Tells the henchmen to be silent and not talk. +const int AI_MODE_CHECK_ATTACK = 0x00800000; // Will only engage in combats they think they can win. +const int AI_MODE_IGNORE_ASSOCIATES = 0x01000000; // Will ignore associates in combat. +//const int AI_MODE_ = 0x02000000; // Not used. +//const int AI_MODE_ = 0x04000000; // Not used. +//const int AI_MODE_ = 0x08000000; // Not used. +//const int AI_MODE_ = 0x10000000; // Not used. +//const int AI_MODE_ = 0x20000000; // Not used. +//const int AI_MODE_ = 0x40000000; // Not used. +//const int AI_MODE_ = 0x80000000; // Not used. +// Bitwise constants for Associate magic modes that are used with Get/SetAssociateMagicMode(). +const string sMagicModeVarname = "ASSOCIATE_MAGIC_MODES"; +const int AI_MAGIC_BUFF_MASTER = 0x00000001; // Buffs master before other allies. +const int AI_MAGIC_NO_MAGIC = 0x00000002; // Will not use any magic (Spells, abilities). +const int AI_MAGIC_DEFENSIVE_CASTING = 0x00000004; // Will only cast defensive spells. +const int AI_MAGIC_OFFENSIVE_CASTING = 0x00000008; // Will only cast offensive spells. +const int AI_MAGIC_STOP_DISPEL = 0x00000010; // Will not cast dispel type spells. +const int AI_MAGIC_BUFF_AFTER_REST = 0x00000020; // Will buff the party after resting. +const int AI_MAGIC_NO_MAGIC_ITEMS = 0x00000040; // Will not use magic items in combat. +const int AI_MAGIC_CURE_SPELLS_OFF = 0x00000080; // Will not cast cure spells. +const int AI_MAGIC_EFFECT_ICON_REPORT = 0x00000100; // Sets each player to report Effect Icons to chat. +//const int = 0x00000200; // Not used. +//const int = 0x00000400; // Not used. +const int AI_MAGIC_NO_SPONTANEOUS_CURE = 0x00000800; // Caster will stop using spontaneous cure spells. +//const int AI_MAGIC_ = 0x00001000; // Not used. +//const int AI_MAGIC_ = 0x00002000; // Not used. +//const int AI_MAGIC_ = 0x00004000; // Not used. +//const int AI_MAGIC_ = 0x00008000; // Not used. +//const int AI_MAGIC_ = 0x00010000; // Not used. +//const int AI_MAGIC_ = 0x00020000; // Not used. +//const int AI_MAGIC_ = 0x00040000; // Not used. +//const int AI_MAGIC_ = 0x00080000; // Not used. +//const int AI_MAGIC_ = 0x00100000; // Not used. +//const int AI_MAGIC_ = 0x00200000; // Not used. +//const int AI_MAGIC_ = 0x00400000; // Not used. +//const int AI_MAGIC_ = 0x00800000; // Not used. +//const int AI_MAGIC_ = 0x01000000; // Not used. +//const int AI_MAGIC_ = 0x02000000; // Not used. +//const int AI_MAGIC_ = 0x04000000; // Not used. +//const int AI_MAGIC_ = 0x08000000; // Not used. +//const int AI_MAGIC_ = 0x10000000; // Not used. +//const int AI_MAGIC_ = 0x20000000; // Not used. +//const int AI_MAGIC_ = 0x40000000; // Not used. +//const int AI_MAGIC_ = 0x80000000; // Not used. +// Use by NUI windows to stop saving move states while loading. +const string AI_NO_NUI_SAVE = "AI_NO_NUI_SAVE"; +// Bitwise menu constants for Widget buttons that are used with Get/SetAssociateWidgetButtons(). +const string sWidgetButtonsVarname = "ASSOCIATE_WIDGET_BUTTONS"; +const int BTN_WIDGET_OFF = 0x00000001; // Removes the widget from the screen, For PC it removes all associates. +const int BTN_WIDGET_LOCK = 0x00000002; // Locks the widget to the current coordinates. +const int BTN_CMD_GUARD = 0x00000004; // Command associates to Guard Me. PC widget only. +const int BTN_CMD_FOLLOW = 0x00000008; // Command associates to Follow. PC widget only. +const int BTN_CMD_HOLD = 0x00000010; // Command associates to Stand Ground. PC widget only. +const int BTN_CMD_ATTACK = 0x00000020; // Command associates to Attack Nearest. PC widget only. +const int BTN_BUFF_REST = 0x00000040; // Buffs with long duration spells after resting. Associate widget only. +const int BTN_BUFF_SHORT = 0x00000080; // Buffs with short duration spells. +const int BTN_BUFF_LONG = 0x00000100; // Buffs with long duration spells. +const int BTN_BUFF_ALL = 0x00000200; // Buffs with all spells. +const int BTN_CMD_ACTION = 0x00000400; // Command associate to do an action. +const int BTN_CMD_GHOST_MODE = 0x00000800; // Toggle's associates ghost mode. +const int BTN_CMD_AI_SCRIPT = 0x00001000; // Toggle's special tactics ai scripts. +const int BTN_CMD_PLACE_TRAP = 0x00002000; // A trapper may place traps. +const int BTN_CMD_CAMERA = 0x00004000; // Places camera view on associate. +const int BTN_CMD_INVENTORY = 0x00008000; // Opens inventory of associate. +const int BTN_CMD_FAMILIAR = 0x00010000; // Summons familiar. +const int BTN_CMD_COMPANION = 0x00020000; // Summons Companion. +const int BTN_CMD_SEARCH = 0x00040000; // Command all associates to use search mode. PC widget only. +const int BTN_CMD_STEALTH = 0x00080000; // Command all associates to use stealth mode. PC widget only. +const int BTN_CMD_SCOUT = 0x00100000; // Command associate to scout ahead of the part. +const int BTN_CMD_SPELL_WIDGET = 0x00200000; // Allows adding or removing spells from Spell Widget. +const int BTN_CMD_JUMP_TO = 0x00400000; // Player can make associates jump to them. +const int BTN_WIDGET_VERTICAL = 0x80000000; // Widget will be displayed vertical. +// Bitwise menu constants for Associate AI buttons that are used with Get/SetAssociateAIButtons(). +const string sAIButtonsVarname = "ASSOCIATE_AI_BUTTONS"; +const int BTN_AI_FOR_PC = 0x00000001; // PC use AI. PC widget only. +const int BTN_AI_USE_RANGED = 0x00000002; // AI uses ranged attacks. +const int BTN_AI_USE_SEARCH = 0x00000004; // AI uses Search. +const int BTN_AI_USE_STEALTH = 0x00000008; // AI uses Stealth. +const int BTN_AI_REMOVE_TRAPS = 0x00000010; // AI seeks out and removes traps. +const int BTN_AI_PICK_LOCKS = 0x00000020; // AI will attempt to pick locks. +const int BTN_AI_MAGIC_LEVEL = 0x00000040; // Increase chance to use magic in battle. +const int BTN_AI_NO_SPONTANEOUS = 0x00000080; // Stops the use of spontaneous spells. +const int BTN_AI_NO_MAGIC_USE = 0x00000100; // Will not use magic in battle. +const int BTN_AI_NO_MAGIC_ITEM_USE = 0x00000200; // Will not use magic items in battle. +const int BTN_AI_DEF_MAGIC_USE = 0x00000400; // Will use Defensive spells only in battle. +const int BTN_AI_OFF_MAGIC_USE = 0x00000800; // Will use Offensive spells only in battle. +const int BTN_AI_LOOT = 0x00001000; // Auto picking up loot on/off. +const int BTN_AI_FOLLOW_TARGET = 0x00002000; // Selects a target to follow. +const int BTN_AI_HEAL_OUT = 0x00004000; // Increase minimum hp required before ai heals out of combat. +const int BTN_AI_PERC_RANGE = 0x00008000; // Adjust the perception range of the henchman. +const int BTN_AI_HEAL_IN = 0x00010000; // Increase minimum hp required before ai heals in combat. +const int BTN_AI_OPEN_DOORS = 0x00020000; // AI will open all closed doors. +const int BTN_AI_STOP_SELF_HEALING = 0x00040000; // Stops AI from using any healing on self. +const int BTN_AI_STOP_PARTY_HEALING = 0x00080000; // Stops AI from using any healing on party. +const int BTN_AI_IGNORE_ASSOCIATES = 0x00100000; // AI will deprioritize enemy associates. +const int BTN_AI_STOP_CURE_SPELLS = 0x00200000; // AI uses cure spells. +const int BTN_AI_STOP_WEAPON_EQUIP = 0x00400000; // AI can equip different weapons. +const int BTN_AI_IGNORE_TRAPS = 0x00800000; // AI will ignore traps on the floor. +//const int BTN_AI = 0x01000000; // Not used. +//const int BTN_AI = 0x02000000; // Not used. +const int BTN_AI_BASH_LOCKS = 0x04000000; // AI will attempt to bash any locks they can't get past. +const int BTN_AI_REDUCE_SPEECH = 0x08000000; // Reduce the associates speaking. +// Bitwise menu constants for DM access for players Widget buttons uses BTN_CMD and BTN_BUFF bitwise see above. +const string sDMWidgetAccessVarname = "AI_RULES_WIDGET_BUTTONS_ACCESS"; +// Bitwise menu constants for DM access for players AI buttons uses BTN_AI bitwise see above. +const string sDMAIAccessVarname = "AI_RULES_AI_BUTTONS_ACCESS"; +// Variable name for DM widget buttons. +const string sDMWidgetButtonVarname = "DM_WIDGET_BUTTONS"; +// DM Widget buttons states. +const int BTN_DM_WIDGET_OFF = 0x00000001; // Removes the widget from the screen, For PC it removes all associates. +const int BTN_DM_WIDGET_LOCK = 0x00000002; // Locks the widget to the current coordinates. +const int BTN_DM_CMD_GROUP1 = 0x00000004; // Does all the group 1 commands. +const int BTN_DM_CMD_GROUP2 = 0x00000008; // Does all the group 2 commands. +const int BTN_DM_CMD_GROUP3 = 0x00000010; // Does all the group 3 commands. +const int BTN_DM_CMD_GROUP4 = 0x00000020; // Does all the group 4 commands. +const int BTN_DM_CMD_GROUP5 = 0x00000040; // Does all the group 5 commands. +const int BTN_DM_CMD_GROUP6 = 0x00000080; // Does all the group 6 commands. +const int BTN_DM_CMD_CAMERA = 0x00000100; // Selects new object to hold the camera view. +const int BTN_DM_CMD_INVENTORY = 0x00000200; // Selects a creature to open the inventory of. +const int BTN_DM_CMD_MEMORIZE = 0x00000400; // Allows associate to change memorized spells. +// Bitwise constants for Associate loot options that are used with Get/SetAssociateLootMode(). +const string sLootFilterVarname = "ASSOCIATE_LOOT_MODES"; +const int AI_LOOT_PLOT = 0x00000001; +const int AI_LOOT_WEAPONS = 0x00000002; +const int AI_LOOT_ARMOR = 0x00000004; +const int AI_LOOT_SHIELDS = 0x00000008; +const int AI_LOOT_HEADGEAR = 0x00000010; +const int AI_LOOT_BELTS = 0x00000020; +const int AI_LOOT_BOOTS = 0x00000040; +const int AI_LOOT_CLOAKS = 0x00000080; +const int AI_LOOT_GLOVES = 0x00000100; +const int AI_LOOT_JEWELRY = 0x00000200; +const int AI_LOOT_POTIONS = 0x00000400; +const int AI_LOOT_SCROLLS = 0x00000800; +const int AI_LOOT_WANDS_RODS_STAVES = 0x00001000; +const int AI_LOOT_GEMS = 0x00002000; +const int AI_LOOT_MISC = 0x00004000; +const int AI_LOOT_ARROWS = 0x00008000; +const int AI_LOOT_BOLTS = 0x00010000; +const int AI_LOOT_BULLETS = 0x00020000; +const int AI_LOOT_GIVE_TO_PC = 0x80000000; +// Default value for all loot filters to be on. +const int AI_LOOT_ALL_ON = 262143; +// Variable to keep track of who is in ghost mode. +const string sGhostModeVarname = "AI_GHOST_MODE_ON"; +// Variables for gold piece value to pickup items. +const string AI_MIN_GOLD_ = "AI_MIN_GOLD_"; +// Variable used to limit the spamming of NUI buttons. +const string AI_DELAY_NUI_USE = "AI_DELAY_NUI_USE"; +// Variable for maximum weight to pickup from looting. +const string AI_MAX_LOOT_WEIGHT = "AI_MAX_LOOT_WEIGHT"; +// Variable to change the size of the widget buttons. +const string AI_WIDGET_BUTTON_SIZE = "AI_WIDGET_BUTTON_SIZE"; +// Variable to change the difficulty so a player can adjust spell usage. +const string AI_DIFFICULTY_ADJUSTMENT = "AI_DIFFICULTY_ADJUSTMENT"; +// Variable to change the Healing % limit for out of combat. +const string AI_HEAL_OUT_OF_COMBAT_LIMIT = "AI_HEAL_OUT_OF_COMBAT_LIMIT"; +// Variable to change the Healing % limit for in combat. +const string AI_HEAL_IN_COMBAT_LIMIT = "AI_HEAL_IN_COMBAT_LIMIT"; +// Variable to change the looting range. +const string AI_LOOT_CHECK_RANGE = "AI_LOOT_CHECK_RANGE"; +// Variable to change the lock checking range. +const string AI_LOCK_CHECK_RANGE = "AI_LOCK_CHECK_RANGE"; +// Variable to change the trap checking range. +const string AI_TRAP_CHECK_RANGE = "AI_TRAP_CHECK_RANGE"; +// Variable to change the range an associate follows the pc. +const string AI_FOLLOW_RANGE = "AI_FOLLOW_RANGE"; +// Variable that holds the target for an associate to follow. +const string AI_FOLLOW_TARGET = "AI_FOLLOW_TARGET"; +// Variable that holds the perception range of associates i.e. 8, 9, 10, 11. +const string AI_ASSOCIATE_PERCEPTION = "AI_PERCEPTION_RANGE"; +// Variable that holds the perception distance of associates i.e. 30.0 meters. +const string AI_ASSOC_PERCEPTION_DISTANCE = "AI_ASSOC_PERCEPTION_DISTANCE"; +// Variable that holds the open doors range of the henchman. +const string AI_OPEN_DOORS_RANGE = "AI_OPEN_DOORS_RANGE"; +// Variable that holds the Spell widgets json data. +const string AI_SPELLS_WIDGET = "AI_SPELLS_WIDGET"; +// The number of Buff Groups +const int AI_BUFF_GROUPS = -17; +// Variable name used to keep track if we have set our talents. +const string AI_TALENTS_SET = "AI_TALENTS_SET"; +// New talent categories +const string AI_TALENT_ENHANCEMENT = "E"; +const string AI_TALENT_PROTECTION = "P"; +const string AI_TALENT_SUMMON = "S"; +const string AI_TALENT_HEALING = "H"; +const string AI_TALENT_CURE = "C"; +const string AI_TALENT_INDISCRIMINANT_AOE = "I"; +const string AI_TALENT_DISCRIMINANT_AOE = "D"; +const string AI_TALENT_RANGED = "R"; +const string AI_TALENT_TOUCH = "T"; +// Talent types. +const int AI_TALENT_TYPE_SPELL = 1; +const int AI_TALENT_TYPE_SP_ABILITY = 2; +const int AI_TALENT_TYPE_FEAT = 3; +const int AI_TALENT_TYPE_ITEM = 4; +// Variable name used to have associates fight the pc's selected target. +const string AI_PC_LOCKED_TARGET = "AI_PC_LOCKED_TARGET"; +// Variable name of json talent immunity. +const string AI_TALENT_IMMUNITY = "AI_TALENT_IMMUNITY"; +// Variables keeps track of the maximum level for the talent category. +const string AI_MAX_TALENT = "AI_MAX_TALENT_"; +// Backward compatability constants. +const int X2_EVENT_CONCENTRATION_BROKEN = 12400; +// Variable set on the module if the module is using PRC. +const string AI_USING_PRC = "AI_USING_PRC"; +// Variable that sets if the rules have been added to the module. +const string AI_RULES_SET = "AI_RULES_SET"; +// Variable that tells us that oCreature has run our OnSpawn event. +const string AI_ONSPAWN_EVENT = "AI_ONSPAWN_EVENT"; +// Variable used to define a creatures unique Tag for widgets. +const string AI_TAG = "AI_TAG"; +// Variable that saves any module target event script so we can pass it along. +const string AI_MODULE_TARGET_EVENT = "AI_MODULE_TARGET_EVENT"; +// Variable for plugins to inject Targeting mode code into PEPS. +const string AI_PLUGIN_TARGET_SCRIPT = "AI_PLUGIN_TARGET_SCRIPT"; +// Variable for PEPS to inject effect icons NUI information. +const string AI_MODULE_GUI_EVENT = "AI_MODULE_GUI_EVENT"; +// Variable used on the player to define the targeting action in the OnPlayerTarget event script. +const string AI_TARGET_MODE = "AI_TARGET_MODE"; +// Variable used on the player to define which associate triggered the OnPlayer Target. +const string AI_TARGET_ASSOCIATE = "AI_TARGET_ASSOCIATE"; +// Bitwise constants for immune damage item properties that is used with Get/SetItemProperty(). +const string sIPImmuneVarname = "AI_IP_IMMUNE"; +// Bitwise constants for resisted damage item properties that is used with Get/SetItemProperty(). +const string sIPResistVarname = "AI_IP_RESIST"; +// Variable name for the Int constant for reduced damage item property set to the bonus of the weapon required. +const string sIPReducedVarname = "AI_IP_REDUCED"; +// Variable name for the Int (Bool) constant for the haste item property. +const string sIPHasHasteVarname = "AI_IP_HAS_HASTE"; +// Variable name used to hold the party xp base needed to adjust party xp. +const string AI_BASE_PARTY_SCALE_XP = "AI_BASE_PARTY_SCALE_XP"; +//***************************** AI RULES CONSTANTS ***************************** +// Variable name set to a creatures full name to set debugging on. +const string AI_RULE_DEBUG_CREATURE = "AI_RULE_DEBUG_CREATURE"; +// Moral checks on or off. +const string AI_RULE_MORAL_CHECKS = "AI_RULE_MORAL_CHECKS"; +// Allows monsters to prebuff before combat starts. +const string AI_RULE_BUFF_MONSTERS = "AI_RULE_BUFF_MONSTERS"; +// Allows monsters to use the ambush AI scripts. +const string AI_RULE_AMBUSH = "AI_RULE_AMBUSH"; +// Enemies may summon familiars and Animal companions and will be randomized. +const string AI_RULE_SUMMON_COMPANIONS = "AI_RULE_SUMMON_COMPANIONS"; +// Allows monsters cast summons spells when prebuffing. +const string AI_RULE_PRESUMMON = "AI_RULE_PRESUMMON"; +// Allow the AI move during combat base on the situation and action taking. +const string AI_RULE_ADVANCED_MOVEMENT = "AI_RULE_ADVANCED_MOVEMENT"; +// Follow Item Level Restrictions for monsters/associates. +// Usually off in Single player and on in Multi player. +const string AI_RULE_ILR = "AI_RULE_ILR"; +// Allow the AI to use Use Magic Device. +const string AI_RULE_ALLOW_UMD = "AI_RULE_ALLOW_UMD"; +// Allow the AI to use healing kits. +const string AI_RULE_HEALERSKITS = "AI_RULE_HEALERSKITS"; +// Summoned associates are permanent and don't disappear when the caster dies. +const string AI_RULE_PERM_ASSOC = "AI_RULE_PERM_ASSOC"; +// Monster AI's chance to attack the weakest target instead of the nearest. +const string AI_RULE_AI_DIFFICULTY = "AI_RULE_AI_DIFFICULTY"; +// Variable that can change the distance creatures will come and attack after +// hearing a shout from an ally that sees or hears an enemy. +// Or when searching for an invisible, heard enemy. +// 10.0 Short, 30.0 Average, 40.0 Long, 60.0 Huge. +const string AI_RULE_PERCEPTION_DISTANCE = "AI_RULE_PERCEPTION_DISTANCE"; +// Enemy corpses remain on the floor instead of dissappearing. +const string AI_RULE_CORPSES_STAY = "AI_RULE_CORPSES_STAY"; +// Monsters will wander around when not in combat. +const string AI_RULE_WANDER = "AI_RULE_WANDER"; +// Increase the number of encounter creatures. +const string AI_INCREASE_ENC_MONSTERS = "AI_INCREASE_ENC_MONSTERS"; +// Increase all monsters hitpoints by this percentage. +const string AI_INCREASE_MONSTERS_HP = "AI_INCREASE_MONSTERS_HP"; +// Variable that can change the distance monsters can hear and see. +const string AI_RULE_MON_PERC_DISTANCE = "AI_RULE_MON_PERC_DISTANCE"; +// Variable name set to hold the maximum number of henchman the player wants. +const string AI_RULE_MAX_HENCHMAN = "AI_RULE_MAX_HENCHMAN"; +// Variable name set to hold the distance monsters can wander away. +const string AI_RULE_WANDER_DISTANCE = "AI_RULE_WANDER_DISTANCE"; +// Variable name set to allow wandering monsters to open doors. +const string AI_RULE_OPEN_DOORS = "AI_RULE_OPEN_DOORS"; +// Variable name set to hold the modules default xp scale for use later. +const string AI_RULE_DEFAULT_XP_SCALE = "AI_RULE_DEFAULT_XP_SCALE"; +// Variable name set to allow the game to regulate experience based on party size. +const string AI_RULE_PARTY_SCALE = "AI_RULE_PARTY_SCALE"; +// Variable name set to restrict the AI's use of Darkness. +const string AI_RULE_RESTRICTED_SPELLS = "AI_RULE_RESTRICTED_SPELLS"; +/*/ Special behavior constants from x0_i0_behavior +const int NW_FLAG_BEHAVIOR_SPECIAL = 0x00000001; +//Will always attack regardless of faction +const int NW_FLAG_BEHAVIOR_CARNIVORE = 0x00000002; +//Will only attack if approached +const int NW_FLAG_BEHAVIOR_OMNIVORE = 0x00000004; +//Will never attack. Will alway flee. +const int NW_FLAG_BEHAVIOR_HERBIVORE = 0x00000008; +// This is the name of the local variable that holds the spawn-in conditions +const string sSpawnCondVarname = "NW_GENERIC_MASTER"; +// The available spawn-in conditions from x0_i0_spawncond +const int NW_FLAG_ESCAPE_RETURN = 0x00000020; //Failed +const int NW_FLAG_ESCAPE_LEAVE = 0x00000040; +const int NW_FLAG_TELEPORT_RETURN = 0x00000080; //Failed +const int NW_FLAG_TELEPORT_LEAVE = 0x00000100; +const int NW_FLAG_END_COMBAT_ROUND_EVENT = 0x00004000; +const int NW_FLAG_ON_DIALOGUE_EVENT = 0x00008000; +const int NW_FLAG_AMBIENT_ANIMATIONS = 0x00080000; +const int NW_FLAG_HEARTBEAT_EVENT = 0x00100000; +const int NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS = 0x00200000; +const int NW_FLAG_DAY_NIGHT_POSTING = 0x00400000; +const int NW_FLAG_AMBIENT_ANIMATIONS_AVIAN = 0x00800000; +const string sWalkwayVarname = "NW_WALK_CONDITION"; +// If set, the creature's waypoints have been initialized. +const int NW_WALK_FLAG_INITIALIZED = 0x00000001; +// If set, the creature will walk its waypoints constantly, +// moving on in each OnHeartbeat event. Otherwise, +// it will walk to the next only when triggered by an +// OnPerception event. +const int NW_WALK_FLAG_CONSTANT = 0x00000002; +// Set when the creature is walking day waypoints. +const int NW_WALK_FLAG_IS_DAY = 0x00000004; +// Set when the creature is walking back +const int NW_WALK_FLAG_BACKWARDS = 0x00000008; diff --git a/src/module/nss/0i_gui_events.nss b/src/module/nss/0i_gui_events.nss new file mode 100644 index 0000000..4628cf3 --- /dev/null +++ b/src/module/nss/0i_gui_events.nss @@ -0,0 +1,1032 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_gui_events +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts for all gui events. See also 0e_gui_events + + GUI Events: + GUIEVENT_EFFECTICON_CLICK: For displaying icon information. + + This was built by DAZ all credit to him. + I just changed it from PostString to a NUI menu. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_constants" +#include "0i_nui" +void ai_SetupModuleGUIEvents(object oCreature) +{ + object oModule = GetModule(); + string sModuleGUIEvents = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_GUIEVENT); + if(sModuleGUIEvents != "" || sModuleGUIEvents != "0e_gui_events") + { + SetLocalString(oModule, AI_MODULE_GUI_EVENT, sModuleGUIEvents); + } + SetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_GUIEVENT, "0e_gui_events"); +} +int EffectIconToEffectType(int nEffectIcon) +{ + switch (nEffectIcon) + { + case EFFECT_ICON_INVALID: return EFFECT_TYPE_INVALIDEFFECT; + + // *** No Extra Stats + case EFFECT_ICON_BLIND: return EFFECT_TYPE_BLINDNESS; + case EFFECT_ICON_CHARMED: return EFFECT_TYPE_CHARMED; + case EFFECT_ICON_CONFUSED: return EFFECT_TYPE_CONFUSED; + case EFFECT_ICON_FRIGHTENED: return EFFECT_TYPE_FRIGHTENED; + case EFFECT_ICON_DOMINATED: return EFFECT_TYPE_DOMINATED; + case EFFECT_ICON_PARALYZE: return EFFECT_TYPE_PARALYZE; + case EFFECT_ICON_DAZED: return EFFECT_TYPE_DAZED; + case EFFECT_ICON_STUNNED: return EFFECT_TYPE_STUNNED; + case EFFECT_ICON_SLEEP: return EFFECT_TYPE_SLEEP; + case EFFECT_ICON_SILENCE: return EFFECT_TYPE_SILENCE; + case EFFECT_ICON_TURNED: return EFFECT_TYPE_TURNED; + case EFFECT_ICON_HASTE: return EFFECT_TYPE_HASTE; + case EFFECT_ICON_SLOW: return EFFECT_TYPE_SLOW; + case EFFECT_ICON_ENTANGLE: return EFFECT_TYPE_ENTANGLE; + case EFFECT_ICON_DEAF: return EFFECT_TYPE_DEAF; + case EFFECT_ICON_DARKNESS: return EFFECT_TYPE_DARKNESS; + case EFFECT_ICON_POLYMORPH: return EFFECT_TYPE_POLYMORPH; + case EFFECT_ICON_SANCTUARY: return EFFECT_TYPE_SANCTUARY; + case EFFECT_ICON_TRUESEEING: return EFFECT_TYPE_TRUESEEING; + case EFFECT_ICON_SEEINVISIBILITY: return EFFECT_TYPE_SEEINVISIBLE; + case EFFECT_ICON_ETHEREALNESS: return EFFECT_TYPE_ETHEREAL; + case EFFECT_ICON_PETRIFIED: return EFFECT_TYPE_PETRIFY; + // *** + + case EFFECT_ICON_DAMAGE_RESISTANCE: return EFFECT_TYPE_DAMAGE_RESISTANCE; + case EFFECT_ICON_REGENERATE: return EFFECT_TYPE_REGENERATE; + case EFFECT_ICON_DAMAGE_REDUCTION: return EFFECT_TYPE_DAMAGE_REDUCTION; + case EFFECT_ICON_TEMPORARY_HITPOINTS: return EFFECT_TYPE_TEMPORARY_HITPOINTS; + case EFFECT_ICON_IMMUNITY: return EFFECT_TYPE_IMMUNITY; + case EFFECT_ICON_POISON: return EFFECT_TYPE_POISON; + case EFFECT_ICON_DISEASE: return EFFECT_TYPE_DISEASE; + case EFFECT_ICON_CURSE: return EFFECT_TYPE_CURSE; + case EFFECT_ICON_ATTACK_INCREASE: return EFFECT_TYPE_ATTACK_INCREASE; + case EFFECT_ICON_ATTACK_DECREASE: return EFFECT_TYPE_ATTACK_DECREASE; + case EFFECT_ICON_DAMAGE_INCREASE: return EFFECT_TYPE_DAMAGE_INCREASE; + case EFFECT_ICON_DAMAGE_DECREASE: return EFFECT_TYPE_DAMAGE_DECREASE; + case EFFECT_ICON_AC_INCREASE: return EFFECT_TYPE_AC_INCREASE; + case EFFECT_ICON_AC_DECREASE: return EFFECT_TYPE_AC_DECREASE; + case EFFECT_ICON_MOVEMENT_SPEED_INCREASE: return EFFECT_TYPE_MOVEMENT_SPEED_INCREASE; + case EFFECT_ICON_MOVEMENT_SPEED_DECREASE: return EFFECT_TYPE_MOVEMENT_SPEED_DECREASE; + case EFFECT_ICON_SAVING_THROW_DECREASE: return EFFECT_TYPE_SAVING_THROW_DECREASE; + case EFFECT_ICON_SPELL_RESISTANCE_INCREASE: return EFFECT_TYPE_SPELL_RESISTANCE_INCREASE; + case EFFECT_ICON_SPELL_RESISTANCE_DECREASE: return EFFECT_TYPE_SPELL_RESISTANCE_DECREASE; + case EFFECT_ICON_SKILL_INCREASE: return EFFECT_TYPE_SKILL_INCREASE; + case EFFECT_ICON_SKILL_DECREASE: return EFFECT_TYPE_SKILL_DECREASE; + case EFFECT_ICON_ELEMENTALSHIELD: return EFFECT_TYPE_ELEMENTALSHIELD; + case EFFECT_ICON_LEVELDRAIN: return EFFECT_TYPE_NEGATIVELEVEL; + case EFFECT_ICON_SPELLLEVELABSORPTION: return EFFECT_TYPE_SPELLLEVELABSORPTION; + case EFFECT_ICON_SPELLIMMUNITY: return EFFECT_TYPE_SPELL_IMMUNITY; + case EFFECT_ICON_CONCEALMENT: return EFFECT_TYPE_CONCEALMENT; + case EFFECT_ICON_EFFECT_SPELL_FAILURE: return EFFECT_TYPE_SPELL_FAILURE; + + case EFFECT_ICON_INVISIBILITY: + case EFFECT_ICON_IMPROVEDINVISIBILITY: return EFFECT_TYPE_INVISIBILITY; + + case EFFECT_ICON_ABILITY_INCREASE_STR: + case EFFECT_ICON_ABILITY_INCREASE_DEX: + case EFFECT_ICON_ABILITY_INCREASE_CON: + case EFFECT_ICON_ABILITY_INCREASE_INT: + case EFFECT_ICON_ABILITY_INCREASE_WIS: + case EFFECT_ICON_ABILITY_INCREASE_CHA: return EFFECT_TYPE_ABILITY_INCREASE; + + case EFFECT_ICON_ABILITY_DECREASE_STR: + case EFFECT_ICON_ABILITY_DECREASE_CHA: + case EFFECT_ICON_ABILITY_DECREASE_DEX: + case EFFECT_ICON_ABILITY_DECREASE_CON: + case EFFECT_ICON_ABILITY_DECREASE_INT: + case EFFECT_ICON_ABILITY_DECREASE_WIS: return EFFECT_TYPE_ABILITY_DECREASE; + + case EFFECT_ICON_IMMUNITY_ALL: + case EFFECT_ICON_IMMUNITY_MIND: + case EFFECT_ICON_IMMUNITY_POISON: + case EFFECT_ICON_IMMUNITY_DISEASE: + case EFFECT_ICON_IMMUNITY_FEAR: + case EFFECT_ICON_IMMUNITY_TRAP: + case EFFECT_ICON_IMMUNITY_PARALYSIS: + case EFFECT_ICON_IMMUNITY_BLINDNESS: + case EFFECT_ICON_IMMUNITY_DEAFNESS: + case EFFECT_ICON_IMMUNITY_SLOW: + case EFFECT_ICON_IMMUNITY_ENTANGLE: + case EFFECT_ICON_IMMUNITY_SILENCE: + case EFFECT_ICON_IMMUNITY_STUN: + case EFFECT_ICON_IMMUNITY_SLEEP: + case EFFECT_ICON_IMMUNITY_CHARM: + case EFFECT_ICON_IMMUNITY_DOMINATE: + case EFFECT_ICON_IMMUNITY_CONFUSE: + case EFFECT_ICON_IMMUNITY_CURSE: + case EFFECT_ICON_IMMUNITY_DAZED: + case EFFECT_ICON_IMMUNITY_ABILITY_DECREASE: + case EFFECT_ICON_IMMUNITY_ATTACK_DECREASE: + case EFFECT_ICON_IMMUNITY_DAMAGE_DECREASE: + case EFFECT_ICON_IMMUNITY_DAMAGE_IMMUNITY_DECREASE: + case EFFECT_ICON_IMMUNITY_AC_DECREASE: + case EFFECT_ICON_IMMUNITY_MOVEMENT_SPEED_DECREASE: + case EFFECT_ICON_IMMUNITY_SAVING_THROW_DECREASE: + case EFFECT_ICON_IMMUNITY_SPELL_RESISTANCE_DECREASE: + case EFFECT_ICON_IMMUNITY_SKILL_DECREASE: + case EFFECT_ICON_IMMUNITY_KNOCKDOWN: + case EFFECT_ICON_IMMUNITY_NEGATIVE_LEVEL: + case EFFECT_ICON_IMMUNITY_SNEAK_ATTACK: + case EFFECT_ICON_IMMUNITY_CRITICAL_HIT: + case EFFECT_ICON_IMMUNITY_DEATH_MAGIC: return EFFECT_TYPE_IMMUNITY; + + case EFFECT_ICON_SAVING_THROW_INCREASE: + case EFFECT_ICON_REFLEX_SAVE_INCREASED: + case EFFECT_ICON_FORT_SAVE_INCREASED: + case EFFECT_ICON_WILL_SAVE_INCREASED: return EFFECT_TYPE_SAVING_THROW_INCREASE; + + case EFFECT_ICON_DAMAGE_IMMUNITY_INCREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_MAGIC: + case EFFECT_ICON_DAMAGE_IMMUNITY_ACID: + case EFFECT_ICON_DAMAGE_IMMUNITY_COLD: + case EFFECT_ICON_DAMAGE_IMMUNITY_DIVINE: + case EFFECT_ICON_DAMAGE_IMMUNITY_ELECTRICAL: + case EFFECT_ICON_DAMAGE_IMMUNITY_FIRE: + case EFFECT_ICON_DAMAGE_IMMUNITY_NEGATIVE: + case EFFECT_ICON_DAMAGE_IMMUNITY_POSITIVE: + case EFFECT_ICON_DAMAGE_IMMUNITY_SONIC: return EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE; + + case EFFECT_ICON_DAMAGE_IMMUNITY_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_MAGIC_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_ACID_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_COLD_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_DIVINE_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_ELECTRICAL_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_FIRE_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_NEGATIVE_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_POSITIVE_DECREASE: + case EFFECT_ICON_DAMAGE_IMMUNITY_SONIC_DECREASE: return EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE; + + //case EFFECT_ICON_INVULNERABLE: return EFFECT_TYPE_INVULNERABLE; + //case EFFECT_ICON_WOUNDING: return EFFECT_TYPE_INVALIDEFFECT; + //case EFFECT_ICON_TAUNTED: return EFFECT_TYPE_INVALIDEFFECT; + //case EFFECT_ICON_TIMESTOP: return EFFECT_TYPE_TIMESTOP; + //case EFFECT_ICON_BLINDNESS: return EFFECT_TYPE_BLINDNESS; + //case EFFECT_ICON_DISPELMAGICBEST: return EFFECT_TYPE_INVALIDEFFECT; + //case EFFECT_ICON_DISPELMAGICALL: return EFFECT_TYPE_INVALIDEFFECT; + //case EFFECT_ICON_ENEMY_ATTACK_BONUS: return EFFECT_TYPE_INVALIDEFFECT; + //case EFFECT_ICON_FATIGUE: return EFFECT_TYPE_INVALIDEFFECT; + } + return EFFECT_TYPE_INVALIDEFFECT; +} +int AbilityTypeFromEffectIconAbility(int nEffectIcon) +{ + switch (nEffectIcon) + { + case EFFECT_ICON_ABILITY_INCREASE_STR: + case EFFECT_ICON_ABILITY_DECREASE_STR: + return ABILITY_STRENGTH; + case EFFECT_ICON_ABILITY_INCREASE_DEX: + case EFFECT_ICON_ABILITY_DECREASE_DEX: + return ABILITY_DEXTERITY; + case EFFECT_ICON_ABILITY_INCREASE_CON: + case EFFECT_ICON_ABILITY_DECREASE_CON: + return ABILITY_CONSTITUTION; + case EFFECT_ICON_ABILITY_INCREASE_INT: + case EFFECT_ICON_ABILITY_DECREASE_INT: + return ABILITY_INTELLIGENCE; + case EFFECT_ICON_ABILITY_INCREASE_WIS: + case EFFECT_ICON_ABILITY_DECREASE_WIS: + return ABILITY_WISDOM; + case EFFECT_ICON_ABILITY_INCREASE_CHA: + case EFFECT_ICON_ABILITY_DECREASE_CHA: + return ABILITY_CHARISMA; + } + return -1; +} +int DamageTypeFromEffectIconDamageImmunity(int nEffectIcon) +{ + switch (nEffectIcon) + { + case EFFECT_ICON_DAMAGE_IMMUNITY_MAGIC: + case EFFECT_ICON_DAMAGE_IMMUNITY_MAGIC_DECREASE: + return DAMAGE_TYPE_MAGICAL; + case EFFECT_ICON_DAMAGE_IMMUNITY_ACID: + case EFFECT_ICON_DAMAGE_IMMUNITY_ACID_DECREASE: + return DAMAGE_TYPE_ACID; + case EFFECT_ICON_DAMAGE_IMMUNITY_COLD: + case EFFECT_ICON_DAMAGE_IMMUNITY_COLD_DECREASE: + return DAMAGE_TYPE_COLD; + case EFFECT_ICON_DAMAGE_IMMUNITY_DIVINE: + case EFFECT_ICON_DAMAGE_IMMUNITY_DIVINE_DECREASE: + return DAMAGE_TYPE_DIVINE; + case EFFECT_ICON_DAMAGE_IMMUNITY_ELECTRICAL: + case EFFECT_ICON_DAMAGE_IMMUNITY_ELECTRICAL_DECREASE: + return DAMAGE_TYPE_ELECTRICAL; + case EFFECT_ICON_DAMAGE_IMMUNITY_FIRE: + case EFFECT_ICON_DAMAGE_IMMUNITY_FIRE_DECREASE: + return DAMAGE_TYPE_FIRE; + case EFFECT_ICON_DAMAGE_IMMUNITY_NEGATIVE: + case EFFECT_ICON_DAMAGE_IMMUNITY_NEGATIVE_DECREASE: + return DAMAGE_TYPE_NEGATIVE; + case EFFECT_ICON_DAMAGE_IMMUNITY_POSITIVE: + case EFFECT_ICON_DAMAGE_IMMUNITY_POSITIVE_DECREASE: + return DAMAGE_TYPE_POSITIVE; + case EFFECT_ICON_DAMAGE_IMMUNITY_SONIC: + case EFFECT_ICON_DAMAGE_IMMUNITY_SONIC_DECREASE: + return DAMAGE_TYPE_SONIC; + } + return -1; +} + +int ImmunityTypeFromEffectIconImmunity(int nEffectIcon) +{ + switch (nEffectIcon) + { + case EFFECT_ICON_IMMUNITY_MIND: return IMMUNITY_TYPE_MIND_SPELLS; + case EFFECT_ICON_IMMUNITY_POISON: return IMMUNITY_TYPE_POISON; + case EFFECT_ICON_IMMUNITY_DISEASE: return IMMUNITY_TYPE_DISEASE; + case EFFECT_ICON_IMMUNITY_FEAR: return IMMUNITY_TYPE_FEAR; + case EFFECT_ICON_IMMUNITY_TRAP: return IMMUNITY_TYPE_TRAP; + case EFFECT_ICON_IMMUNITY_PARALYSIS: return IMMUNITY_TYPE_PARALYSIS; + case EFFECT_ICON_IMMUNITY_BLINDNESS: return IMMUNITY_TYPE_BLINDNESS; + case EFFECT_ICON_IMMUNITY_DEAFNESS: return IMMUNITY_TYPE_DEAFNESS; + case EFFECT_ICON_IMMUNITY_SLOW: return IMMUNITY_TYPE_SLOW; + case EFFECT_ICON_IMMUNITY_ENTANGLE: return IMMUNITY_TYPE_ENTANGLE; + case EFFECT_ICON_IMMUNITY_SILENCE: return IMMUNITY_TYPE_SILENCE; + case EFFECT_ICON_IMMUNITY_STUN: return IMMUNITY_TYPE_STUN; + case EFFECT_ICON_IMMUNITY_SLEEP: return IMMUNITY_TYPE_SLEEP; + case EFFECT_ICON_IMMUNITY_CHARM: return IMMUNITY_TYPE_CHARM; + case EFFECT_ICON_IMMUNITY_DOMINATE: return IMMUNITY_TYPE_DOMINATE; + case EFFECT_ICON_IMMUNITY_CONFUSE: return IMMUNITY_TYPE_CONFUSED; + case EFFECT_ICON_IMMUNITY_CURSE: return IMMUNITY_TYPE_CURSED; + case EFFECT_ICON_IMMUNITY_DAZED: return IMMUNITY_TYPE_DAZED; + case EFFECT_ICON_IMMUNITY_ABILITY_DECREASE: return IMMUNITY_TYPE_ABILITY_DECREASE; + case EFFECT_ICON_IMMUNITY_ATTACK_DECREASE: return IMMUNITY_TYPE_ATTACK_DECREASE; + case EFFECT_ICON_IMMUNITY_DAMAGE_DECREASE: return IMMUNITY_TYPE_DAMAGE_DECREASE; + case EFFECT_ICON_IMMUNITY_DAMAGE_IMMUNITY_DECREASE: return IMMUNITY_TYPE_DAMAGE_IMMUNITY_DECREASE; + case EFFECT_ICON_IMMUNITY_AC_DECREASE: return IMMUNITY_TYPE_AC_DECREASE; + case EFFECT_ICON_IMMUNITY_MOVEMENT_SPEED_DECREASE: return IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE; + case EFFECT_ICON_IMMUNITY_SAVING_THROW_DECREASE: return IMMUNITY_TYPE_SAVING_THROW_DECREASE; + case EFFECT_ICON_IMMUNITY_SPELL_RESISTANCE_DECREASE: return IMMUNITY_TYPE_SPELL_RESISTANCE_DECREASE; + case EFFECT_ICON_IMMUNITY_SKILL_DECREASE: return IMMUNITY_TYPE_SKILL_DECREASE; + case EFFECT_ICON_IMMUNITY_KNOCKDOWN: return IMMUNITY_TYPE_KNOCKDOWN; + case EFFECT_ICON_IMMUNITY_NEGATIVE_LEVEL: return IMMUNITY_TYPE_NEGATIVE_LEVEL; + case EFFECT_ICON_IMMUNITY_SNEAK_ATTACK: return IMMUNITY_TYPE_SNEAK_ATTACK; + case EFFECT_ICON_IMMUNITY_CRITICAL_HIT: return IMMUNITY_TYPE_CRITICAL_HIT; + case EFFECT_ICON_IMMUNITY_DEATH_MAGIC: return IMMUNITY_TYPE_DEATH; + } + return -1; +} +void ClearLines(object oPlayer) +{ + int nLine, nLines = GetLocalInt(oPlayer, "BUFFINFO_LAST_NUM_LINES"); + for (nLine = 1; nLine <= nLines; nLine++) + { + PostString(oPlayer, "", 10, nLine + 3, SCREEN_ANCHOR_TOP_RIGHT, 0.1f, 0xFFFFFF00, 0xFFFFFF00, nLine); + } +} +void DisplayLine(object oPlayer, int nLine, string sText, int nColor) +{ + PostString(oPlayer, sText, 10, nLine + 3, SCREEN_ANCHOR_TOP_RIGHT, 10.0f, nColor, 0xFFFFFF00, nLine); +} +string SecondsToTimestamp(int nSeconds) +{ + sqlquery sql; + if (nSeconds > 86400) sql = SqlPrepareQueryObject(GetModule(), "SELECT (@seconds / 3600) || ':' || strftime('%M:%S', @seconds / 86400.0);"); + else sql = SqlPrepareQueryObject(GetModule(), "SELECT time(@seconds, 'unixepoch');"); + SqlBindInt(sql, "@seconds", nSeconds); + SqlStep(sql); + return SqlGetString(sql, 0); +} +string Get2DAStrRef(string s2DA, string sColumn, int nRow) +{ + return GetStringByStrRef(StringToInt(Get2DAString(s2DA, sColumn, nRow))); +} +string GetVersusRacialTypeAndAlignment(int nRacialType, int nLawfulChaotic, int nGoodEvil) +{ + string sRacialType = nRacialType == RACIAL_TYPE_INVALID ? "" : Get2DAStrRef("racialtypes", "NamePlural", nRacialType); + string sLawfulChaotic = nLawfulChaotic == ALIGNMENT_LAWFUL ? "Lawful" : nLawfulChaotic == ALIGNMENT_CHAOTIC ? "Chaotic" : ""; + string sGoodEvil = nGoodEvil == ALIGNMENT_GOOD ? "Good" : nGoodEvil == ALIGNMENT_EVIL ? "Evil" : ""; + string sAlignment = sLawfulChaotic + (sLawfulChaotic == "" ? sGoodEvil : (sGoodEvil == "" ? "" : " " + sGoodEvil)); + return (sRacialType != "" || sAlignment != "") ? (" vs. " + sAlignment + (sAlignment == "" ? sRacialType : (sRacialType == "" ? "" : " " + sRacialType))) : ""; +} +string GetModifierType(int nEffectType, int nPlus, int nMinus) +{ + return nEffectType == nPlus ? "+" : nEffectType == nMinus ? "-" : ""; +} +string ACTypeToString(int nACType) +{ + switch (nACType) + { + case AC_DODGE_BONUS: return "Dodge"; + case AC_NATURAL_BONUS: return "Natural"; + case AC_ARMOUR_ENCHANTMENT_BONUS: return "Armor"; + case AC_SHIELD_ENCHANTMENT_BONUS: return "Shield"; + case AC_DEFLECTION_BONUS: return "Deflection"; + } + return ""; +} + +string SavingThrowToString(int nSavingThrow) +{ + switch (nSavingThrow) + { + case SAVING_THROW_ALL: return "All"; + case SAVING_THROW_FORT: return "Fortitude"; + case SAVING_THROW_REFLEX: return "Reflex"; + case SAVING_THROW_WILL: return "Will"; + } + return ""; +} +string SavingThrowTypeToString(int nSavingThrowType) +{ + switch (nSavingThrowType) + { + case SAVING_THROW_TYPE_MIND_SPELLS: return "Mind Spells"; + case SAVING_THROW_TYPE_POISON: return "Poison"; + case SAVING_THROW_TYPE_DISEASE: return "Disease"; + case SAVING_THROW_TYPE_FEAR: return "Fear"; + case SAVING_THROW_TYPE_SONIC: return "Sonic"; + case SAVING_THROW_TYPE_ACID: return "Acid"; + case SAVING_THROW_TYPE_FIRE: return "Fire"; + case SAVING_THROW_TYPE_ELECTRICITY: return "Electricity"; + case SAVING_THROW_TYPE_POSITIVE: return "Positive"; + case SAVING_THROW_TYPE_NEGATIVE: return "Negative"; + case SAVING_THROW_TYPE_DEATH: return "Death"; + case SAVING_THROW_TYPE_COLD: return "Cold"; + case SAVING_THROW_TYPE_DIVINE: return "Divine"; + case SAVING_THROW_TYPE_TRAP: return "Traps"; + case SAVING_THROW_TYPE_SPELL: return "Spells"; + case SAVING_THROW_TYPE_GOOD: return "Good"; + case SAVING_THROW_TYPE_EVIL: return "Evil"; + case SAVING_THROW_TYPE_LAW: return "Lawful"; + case SAVING_THROW_TYPE_CHAOS: return "Chaotic"; + } + return ""; +} +string AbilityToString(int nAbility) +{ + switch (nAbility) + { + case ABILITY_STRENGTH: return "Strength"; + case ABILITY_DEXTERITY: return "Dexterity"; + case ABILITY_CONSTITUTION: return "Constitution"; + case ABILITY_INTELLIGENCE: return "Intelligence"; + case ABILITY_WISDOM: return "Wisdom"; + case ABILITY_CHARISMA: return "Charisma"; + } + return ""; +} +string DamageTypeToString(int nDamageType) +{ + switch (nDamageType) + { + case DAMAGE_TYPE_BLUDGEONING: return "Bludgeoning"; + case DAMAGE_TYPE_PIERCING: return "Piercing"; + case DAMAGE_TYPE_SLASHING: return "Slashing"; + case DAMAGE_TYPE_MAGICAL: return "Magical"; + case DAMAGE_TYPE_ACID: return "Acid"; + case DAMAGE_TYPE_COLD: return "Cold"; + case DAMAGE_TYPE_DIVINE: return "Divine"; + case DAMAGE_TYPE_ELECTRICAL: return "Electrical"; + case DAMAGE_TYPE_FIRE: return "Fire"; + case DAMAGE_TYPE_NEGATIVE: return "Negative"; + case DAMAGE_TYPE_POSITIVE: return "Positive"; + case DAMAGE_TYPE_SONIC: return "Sonic"; + case DAMAGE_TYPE_BASE_WEAPON: return "Base Weapon"; + } + return ""; +} +string SpellSchoolToString(int nSpellSchool) +{ + switch (nSpellSchool) + { + case SPELL_SCHOOL_GENERAL: return "General"; + case SPELL_SCHOOL_ABJURATION: return "Abjuration"; + case SPELL_SCHOOL_CONJURATION: return "Conjuration"; + case SPELL_SCHOOL_DIVINATION: return "Divination"; + case SPELL_SCHOOL_ENCHANTMENT: return "Enchantment"; + case SPELL_SCHOOL_EVOCATION: return "Evocation"; + case SPELL_SCHOOL_ILLUSION: return "Illusion"; + case SPELL_SCHOOL_NECROMANCY: return "Necromancy"; + case SPELL_SCHOOL_TRANSMUTATION: return "Transmutation"; + } + return ""; +} +string MissChanceToString(int nMissChance) +{ + switch (nMissChance) + { + case MISS_CHANCE_TYPE_VS_RANGED: return "vs. Ranged"; + case MISS_CHANCE_TYPE_VS_MELEE: return "vs. Melee"; + } + return ""; +} +void ai_CreateEffectChatReport(object oPlayer, int nEffectIconID) +{ + int nIconEffectType = EffectIconToEffectType(nEffectIconID); + if(nIconEffectType == EFFECT_TYPE_INVALIDEFFECT) return; + int nLine, nIndex, nEffectIndex; + string sColor = AI_COLOR_YELLOW; + int bSkipDisplay, bHasEffect; + int nEffectType, bIsSpellLevelAbsorptionPretendingToBeSpellImmunity; + string sText; + json jEffectID = JsonArray(); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 27 + sText = Get2DAStrRef("effecticons", "StrRef", nEffectIconID); + ai_SendMessages(sText, AI_COLOR_YELLOW, oPlayer); + effect eEffect = GetFirstEffect(oPlayer); + while(GetIsEffectValid(eEffect)) + { + bSkipDisplay = FALSE; + nEffectType = GetEffectType(eEffect); + // Unlimited EffectSpellLevelAbsorption has a SpellImmunity Icon + if (nIconEffectType == EFFECT_TYPE_SPELL_IMMUNITY && GetEffectInteger(eEffect, 3)) + { + bIsSpellLevelAbsorptionPretendingToBeSpellImmunity = TRUE; + nIconEffectType = EFFECT_TYPE_SPELLLEVELABSORPTION; + } + if (nEffectType == nIconEffectType) + { + bHasEffect = TRUE; + int nSpellID = GetEffectSpellId(eEffect); + string sSpellName = nSpellID == -1 ? "" : Get2DAStrRef("spells", "Name", nSpellID); + int bIsPermanentEffect = GetEffectDurationType(eEffect) == DURATION_TYPE_PERMANENT; + int nDurationRemaining = GetEffectDurationRemaining(eEffect); + string sDurationRemaining = bIsPermanentEffect ? "(Permanent)" : "(" + SecondsToTimestamp(nDurationRemaining) + ")"; + if(bIsPermanentEffect) sColor = AI_COLOR_WHITE; + else + { + if(nDurationRemaining < 61) sColor = AI_COLOR_RED; + else if(nDurationRemaining < 300) sColor = AI_COLOR_YELLOW; + else sColor = AI_COLOR_GREEN; + } + string sStats = ""; + string sRacialTypeAlignment = ""; + switch (nEffectType) + { + case EFFECT_TYPE_AC_INCREASE: + case EFFECT_TYPE_AC_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_AC_INCREASE, EFFECT_TYPE_AC_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + ACTypeToString(GetEffectInteger(eEffect, 0)) + " AC"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_ATTACK_INCREASE: + case EFFECT_TYPE_ATTACK_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_ATTACK_INCREASE, EFFECT_TYPE_ATTACK_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) +" AB"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_SAVING_THROW_INCREASE: + case EFFECT_TYPE_SAVING_THROW_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SAVING_THROW_INCREASE, EFFECT_TYPE_SAVING_THROW_DECREASE); + string sSavingThrow = SavingThrowToString(GetEffectInteger(eEffect, 1)); + string sSavingThrowType = SavingThrowTypeToString(GetEffectInteger(eEffect, 2)); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + " " + sSavingThrow + (sSavingThrowType == "" ? "" : " (vs. " + sSavingThrowType + ")"); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4), GetEffectInteger(eEffect, 5)); + break; + } + case EFFECT_TYPE_ABILITY_INCREASE: + case EFFECT_TYPE_ABILITY_DECREASE: + { + int nAbility = AbilityTypeFromEffectIconAbility(nEffectIconID); + + if (nAbility != GetEffectInteger(eEffect, 0)) + bSkipDisplay = TRUE; + else + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_ABILITY_INCREASE, EFFECT_TYPE_ABILITY_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + AbilityToString(nAbility); + } + break; + } + case EFFECT_TYPE_DAMAGE_INCREASE: + case EFFECT_TYPE_DAMAGE_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_DAMAGE_INCREASE, EFFECT_TYPE_DAMAGE_DECREASE); + sStats = sModifier + Get2DAStrRef("iprp_damagecost", "Name", GetEffectInteger(eEffect, 0)) + " (" + DamageTypeToString(GetEffectInteger(eEffect, 1)) + ")"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_SKILL_INCREASE: + case EFFECT_TYPE_SKILL_DECREASE: + { + int nSkill = GetEffectInteger(eEffect, 0); + string sSkill = nSkill == 255 ? "All Skills" : Get2DAStrRef("skills", "Name", nSkill); + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SKILL_INCREASE, EFFECT_TYPE_SKILL_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + sSkill; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_TEMPORARY_HITPOINTS: + { + sStats = "+" + IntToString(GetEffectInteger(eEffect, 0)) + " HitPoints"; + break; + } + case EFFECT_TYPE_DAMAGE_REDUCTION: + { + int nAmount = GetEffectInteger(eEffect, 0); + int nDamagePower = GetEffectInteger(eEffect, 1); + nDamagePower = nDamagePower > 6 ? --nDamagePower : nDamagePower; + int nRemaining = GetEffectInteger(eEffect, 2); + sStats = IntToString(nAmount) + "/+" + IntToString(nDamagePower) + " (" + (nRemaining == 0 ? "Unlimited" : IntToString(nRemaining) + " Damage Remaining") + ")"; + break; + } + case EFFECT_TYPE_DAMAGE_RESISTANCE: + { + int nAmount = GetEffectInteger(eEffect, 1); + int nRemaining = GetEffectInteger(eEffect, 2); + sStats = IntToString(nAmount) + "/- " + DamageTypeToString(GetEffectInteger(eEffect, 0)) + " Resistance (" + (nRemaining == 0 ? "Unlimited" : IntToString(nRemaining) + " Damage Remaining") + ")"; + break; + } + case EFFECT_TYPE_IMMUNITY: + { + int nImmunity = ImmunityTypeFromEffectIconImmunity(nEffectIconID); + + if (nImmunity != GetEffectInteger(eEffect, 0)) + bSkipDisplay = TRUE; + else + { + sStats = Get2DAStrRef("effecticons", "StrRef", nEffectIconID); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + } + break; + } + case EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE: + case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE: + { + int nDamageType = GetEffectInteger(eEffect, 0); + int nDamageTypeFromIcon = DamageTypeFromEffectIconDamageImmunity(nEffectIconID); + + if (nDamageTypeFromIcon != -1 && nDamageType != nDamageTypeFromIcon) + bSkipDisplay = TRUE; + + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE, EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + "% " + DamageTypeToString(nDamageType) + " Damage Immunity"; + break; + } + case EFFECT_TYPE_SPELL_IMMUNITY: + { + sStats = "Spell Immunity: " + Get2DAStrRef("spells", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_SPELLLEVELABSORPTION: + { + int nMaxSpellLevelAbsorbed = GetEffectInteger(eEffect, 0); + int bUnlimited = GetEffectInteger(eEffect, 3); + string sSpellLevel; + switch (nMaxSpellLevelAbsorbed) + { + case 0: sSpellLevel = "Cantrip"; break; + case 1: sSpellLevel = "1st"; break; + case 2: sSpellLevel = "2nd"; break; + case 3: sSpellLevel = "3rd"; break; + default: sSpellLevel = IntToString(nMaxSpellLevelAbsorbed) + "th"; break; + } + sSpellLevel += " Level" + (nMaxSpellLevelAbsorbed == 0 ? "" : " and Below"); + string sSpellSchool = SpellSchoolToString(GetEffectInteger(eEffect, 2)); + string sRemainingSpellLevels = bUnlimited ? "" : "(" + IntToString(GetEffectInteger(eEffect, 1)) + " Spell Levels Remaining)"; + sStats = sSpellLevel + " " + sSpellSchool + " Spell Immunity " + sRemainingSpellLevels; + + if (bIsSpellLevelAbsorptionPretendingToBeSpellImmunity) + nIconEffectType = EFFECT_TYPE_SPELL_IMMUNITY; + else if (bUnlimited && !bIsSpellLevelAbsorptionPretendingToBeSpellImmunity) + bSkipDisplay = TRUE; + + break; + } + case EFFECT_TYPE_REGENERATE: + { + sStats = "+" + IntToString(GetEffectInteger(eEffect, 0)) + " HP / " + FloatToString((GetEffectInteger(eEffect, 1) / 1000.0f), 0, 2) + "s"; + break; + } + case EFFECT_TYPE_POISON: + { + sStats = "Poison: " + Get2DAStrRef("poison", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_DISEASE: + { + sStats = "Disease: " + Get2DAStrRef("disease", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_CURSE: + { + int nAbility; + string sAbilityDecrease; + for (nAbility = 0; nAbility < 6; nAbility++) + { + int nAbilityMod = GetEffectInteger(eEffect, nAbility); + if (nAbilityMod > 0) + { + string sAbility = GetStringLeft(AbilityToString(nAbility), 3); + sAbilityDecrease += "-" + IntToString(nAbilityMod) + " " + sAbility + ", "; + } + } + sAbilityDecrease = GetStringLeft(sAbilityDecrease, GetStringLength(sAbilityDecrease) - 2); + sStats = sAbilityDecrease; + break; + } + case EFFECT_TYPE_MOVEMENT_SPEED_INCREASE: + case EFFECT_TYPE_MOVEMENT_SPEED_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_MOVEMENT_SPEED_INCREASE, EFFECT_TYPE_MOVEMENT_SPEED_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + "% Movement Speed"; + break; + } + case EFFECT_TYPE_ELEMENTALSHIELD: + { + sStats = IntToString(GetEffectInteger(eEffect, 0)) + " + " + Get2DAStrRef("iprp_damagecost", "Name", GetEffectInteger(eEffect, 1)) + " (" + DamageTypeToString(GetEffectInteger(eEffect, 2)) + ")"; + break; + } + case EFFECT_TYPE_NEGATIVELEVEL: + { + sStats = "-" + IntToString(GetEffectInteger(eEffect, 0)) + " Levels"; + break; + } + case EFFECT_TYPE_CONCEALMENT: + { + string sMissChance = MissChanceToString(GetEffectInteger(eEffect, 4) - 1); + sStats = IntToString(GetEffectInteger(eEffect, 0)) + "% Concealment" + (sMissChance == "" ? "" : " (" + sMissChance + ")"); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + break; + } + case EFFECT_TYPE_SPELL_RESISTANCE_INCREASE: + case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SPELL_RESISTANCE_INCREASE, EFFECT_TYPE_SPELL_RESISTANCE_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + " Spell Resistance"; + break; + } + case EFFECT_TYPE_SPELL_FAILURE: + { + sStats = IntToString(GetEffectInteger(eEffect, 0)) + "% Spell Failure (Spell School: " + SpellSchoolToString(GetEffectInteger(eEffect, 1)) + ")"; + break; + } + case EFFECT_TYPE_INVISIBILITY: + { + int nInvisibilityType = GetEffectInteger(eEffect, 0); + if (nEffectIconID == EFFECT_ICON_INVISIBILITY) + bSkipDisplay = nInvisibilityType != INVISIBILITY_TYPE_NORMAL; + else if (nEffectIconID == EFFECT_ICON_IMPROVEDINVISIBILITY) + bSkipDisplay = nInvisibilityType != INVISIBILITY_TYPE_IMPROVED; + if (!bSkipDisplay) + { + sStats = (nInvisibilityType == INVISIBILITY_TYPE_IMPROVED ? "Improved " : "") + "Invisibility"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + } + break; + } + case EFFECT_TYPE_HASTE: + { + sStats = "Hasted"; + } + } + if(!bSkipDisplay) + { + sText = sSpellName + " " + sDurationRemaining + (sStats == "" ? "" : " -> " + sStats + sRacialTypeAlignment); + if(sText != "") + { + ai_SendMessages(sText, sColor, oPlayer); + object oSource = GetEffectCreator(eEffect); + if(GetIsObjectValid(oSource)) + { + sText = GetObjectType(oSource) ? GetName(oSource) : ""; + sText = " Creator: " + sText; + float fLength = IntToFloat(GetStringLength(sText) * 8); + ai_SendMessages(sText, AI_COLOR_YELLOW, oPlayer); + } + } + } + } + nIndex++; + eEffect = GetNextEffect(oPlayer); + } +} +void ai_CreateEffectIconMenu(object oPlayer, int nEffectIconID) +{ + int nIconEffectType = EffectIconToEffectType(nEffectIconID); + if(nIconEffectType == EFFECT_TYPE_INVALIDEFFECT) return; + int nLine, nColor, nIndex, nEffectIndex; + int bSkipDisplay, bHasEffect; + int nEffectType, bIsSpellLevelAbsorptionPretendingToBeSpellImmunity; + string sText; + json jEffectID = JsonArray(); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 27 + sText = Get2DAStrRef("effecticons", "StrRef", nEffectIconID); + json jRow = CreateLabel(JsonArray(), "Effect: " + sText, "lbl_buff_name", 700.0f, 15.0f, NUI_HALIGN_LEFT, NUI_VALIGN_MIDDLE, 0.0); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + float fHeight = 27.0; + effect eEffect = GetFirstEffect(oPlayer); + while(GetIsEffectValid(eEffect)) + { + bSkipDisplay = FALSE; + nEffectType = GetEffectType(eEffect); + // Unlimited EffectSpellLevelAbsorption has a SpellImmunity Icon + if (nIconEffectType == EFFECT_TYPE_SPELL_IMMUNITY && GetEffectInteger(eEffect, 3)) + { + bIsSpellLevelAbsorptionPretendingToBeSpellImmunity = TRUE; + nIconEffectType = EFFECT_TYPE_SPELLLEVELABSORPTION; + } + if (nEffectType == nIconEffectType) + { + bHasEffect = TRUE; + int nSpellID = GetEffectSpellId(eEffect); + string sSpellName = nSpellID == -1 ? "" : Get2DAStrRef("spells", "Name", nSpellID); + int bIsPermanentEffect = GetEffectDurationType(eEffect) == DURATION_TYPE_PERMANENT; + int nDurationRemaining = GetEffectDurationRemaining(eEffect); + string sDurationRemaining = bIsPermanentEffect ? "(Permanent)" : "(" + SecondsToTimestamp(nDurationRemaining) + ")"; + if(bIsPermanentEffect) nColor = 0x0000FFFF; + else + { + float fPercentage = IntToFloat(nDurationRemaining) / IntToFloat(GetEffectDuration(eEffect)); + if(fPercentage > 0.5f) nColor = 0x00FF00FF; + else if(fPercentage < 0.25f) nColor = 0xFF0000FF; + else nColor = 0xFFFF00FF; + } + string sStats = ""; + string sRacialTypeAlignment = ""; + switch (nEffectType) + { + case EFFECT_TYPE_AC_INCREASE: + case EFFECT_TYPE_AC_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_AC_INCREASE, EFFECT_TYPE_AC_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + ACTypeToString(GetEffectInteger(eEffect, 0)) + " AC"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_ATTACK_INCREASE: + case EFFECT_TYPE_ATTACK_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_ATTACK_INCREASE, EFFECT_TYPE_ATTACK_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) +" AB"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_SAVING_THROW_INCREASE: + case EFFECT_TYPE_SAVING_THROW_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SAVING_THROW_INCREASE, EFFECT_TYPE_SAVING_THROW_DECREASE); + string sSavingThrow = SavingThrowToString(GetEffectInteger(eEffect, 1)); + string sSavingThrowType = SavingThrowTypeToString(GetEffectInteger(eEffect, 2)); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + " " + sSavingThrow + (sSavingThrowType == "" ? "" : " (vs. " + sSavingThrowType + ")"); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4), GetEffectInteger(eEffect, 5)); + break; + } + case EFFECT_TYPE_ABILITY_INCREASE: + case EFFECT_TYPE_ABILITY_DECREASE: + { + int nAbility = AbilityTypeFromEffectIconAbility(nEffectIconID); + + if (nAbility != GetEffectInteger(eEffect, 0)) + bSkipDisplay = TRUE; + else + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_ABILITY_INCREASE, EFFECT_TYPE_ABILITY_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + AbilityToString(nAbility); + } + break; + } + case EFFECT_TYPE_DAMAGE_INCREASE: + case EFFECT_TYPE_DAMAGE_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_DAMAGE_INCREASE, EFFECT_TYPE_DAMAGE_DECREASE); + sStats = sModifier + Get2DAStrRef("iprp_damagecost", "Name", GetEffectInteger(eEffect, 0)) + " (" + DamageTypeToString(GetEffectInteger(eEffect, 1)) + ")"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_SKILL_INCREASE: + case EFFECT_TYPE_SKILL_DECREASE: + { + int nSkill = GetEffectInteger(eEffect, 0); + string sSkill = nSkill == 255 ? "All Skills" : Get2DAStrRef("skills", "Name", nSkill); + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SKILL_INCREASE, EFFECT_TYPE_SKILL_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + " " + sSkill; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3), GetEffectInteger(eEffect, 4)); + break; + } + case EFFECT_TYPE_TEMPORARY_HITPOINTS: + { + sStats = "+" + IntToString(GetEffectInteger(eEffect, 0)) + " HitPoints"; + break; + } + case EFFECT_TYPE_DAMAGE_REDUCTION: + { + int nAmount = GetEffectInteger(eEffect, 0); + int nDamagePower = GetEffectInteger(eEffect, 1); + nDamagePower = nDamagePower > 6 ? --nDamagePower : nDamagePower; + int nRemaining = GetEffectInteger(eEffect, 2); + sStats = IntToString(nAmount) + "/+" + IntToString(nDamagePower) + " (" + (nRemaining == 0 ? "Unlimited" : IntToString(nRemaining) + " Damage Remaining") + ")"; + break; + } + case EFFECT_TYPE_DAMAGE_RESISTANCE: + { + int nAmount = GetEffectInteger(eEffect, 1); + int nRemaining = GetEffectInteger(eEffect, 2); + sStats = IntToString(nAmount) + "/- " + DamageTypeToString(GetEffectInteger(eEffect, 0)) + " Resistance (" + (nRemaining == 0 ? "Unlimited" : IntToString(nRemaining) + " Damage Remaining") + ")"; + break; + } + case EFFECT_TYPE_IMMUNITY: + { + int nImmunity = ImmunityTypeFromEffectIconImmunity(nEffectIconID); + + if (nImmunity != GetEffectInteger(eEffect, 0)) + bSkipDisplay = TRUE; + else + { + sStats = Get2DAStrRef("effecticons", "StrRef", nEffectIconID); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + } + break; + } + case EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE: + case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE: + { + int nDamageType = GetEffectInteger(eEffect, 0); + int nDamageTypeFromIcon = DamageTypeFromEffectIconDamageImmunity(nEffectIconID); + + if (nDamageTypeFromIcon != -1 && nDamageType != nDamageTypeFromIcon) + bSkipDisplay = TRUE; + + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE, EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 1)) + "% " + DamageTypeToString(nDamageType) + " Damage Immunity"; + break; + } + case EFFECT_TYPE_SPELL_IMMUNITY: + { + sStats = "Spell Immunity: " + Get2DAStrRef("spells", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_SPELLLEVELABSORPTION: + { + int nMaxSpellLevelAbsorbed = GetEffectInteger(eEffect, 0); + int bUnlimited = GetEffectInteger(eEffect, 3); + string sSpellLevel; + switch (nMaxSpellLevelAbsorbed) + { + case 0: sSpellLevel = "Cantrip"; break; + case 1: sSpellLevel = "1st"; break; + case 2: sSpellLevel = "2nd"; break; + case 3: sSpellLevel = "3rd"; break; + default: sSpellLevel = IntToString(nMaxSpellLevelAbsorbed) + "th"; break; + } + sSpellLevel += " Level" + (nMaxSpellLevelAbsorbed == 0 ? "" : " and Below"); + string sSpellSchool = SpellSchoolToString(GetEffectInteger(eEffect, 2)); + string sRemainingSpellLevels = bUnlimited ? "" : "(" + IntToString(GetEffectInteger(eEffect, 1)) + " Spell Levels Remaining)"; + sStats = sSpellLevel + " " + sSpellSchool + " Spell Immunity " + sRemainingSpellLevels; + + if (bIsSpellLevelAbsorptionPretendingToBeSpellImmunity) + nIconEffectType = EFFECT_TYPE_SPELL_IMMUNITY; + else if (bUnlimited && !bIsSpellLevelAbsorptionPretendingToBeSpellImmunity) + bSkipDisplay = TRUE; + + break; + } + case EFFECT_TYPE_REGENERATE: + { + sStats = "+" + IntToString(GetEffectInteger(eEffect, 0)) + " HP / " + FloatToString((GetEffectInteger(eEffect, 1) / 1000.0f), 0, 2) + "s"; + break; + } + case EFFECT_TYPE_POISON: + { + sStats = "Poison: " + Get2DAStrRef("poison", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_DISEASE: + { + sStats = "Disease: " + Get2DAStrRef("disease", "Name", GetEffectInteger(eEffect, 0)); + break; + } + case EFFECT_TYPE_CURSE: + { + int nAbility; + string sAbilityDecrease; + for (nAbility = 0; nAbility < 6; nAbility++) + { + int nAbilityMod = GetEffectInteger(eEffect, nAbility); + if (nAbilityMod > 0) + { + string sAbility = GetStringLeft(AbilityToString(nAbility), 3); + sAbilityDecrease += "-" + IntToString(nAbilityMod) + " " + sAbility + ", "; + } + } + sAbilityDecrease = GetStringLeft(sAbilityDecrease, GetStringLength(sAbilityDecrease) - 2); + sStats = sAbilityDecrease; + break; + } + case EFFECT_TYPE_MOVEMENT_SPEED_INCREASE: + case EFFECT_TYPE_MOVEMENT_SPEED_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_MOVEMENT_SPEED_INCREASE, EFFECT_TYPE_MOVEMENT_SPEED_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + "% Movement Speed"; + break; + } + case EFFECT_TYPE_ELEMENTALSHIELD: + { + sStats = IntToString(GetEffectInteger(eEffect, 0)) + " + " + Get2DAStrRef("iprp_damagecost", "Name", GetEffectInteger(eEffect, 1)) + " (" + DamageTypeToString(GetEffectInteger(eEffect, 2)) + ")"; + break; + } + case EFFECT_TYPE_NEGATIVELEVEL: + { + sStats = "-" + IntToString(GetEffectInteger(eEffect, 0)) + " Levels"; + break; + } + case EFFECT_TYPE_CONCEALMENT: + { + string sMissChance = MissChanceToString(GetEffectInteger(eEffect, 4) - 1); + sStats = IntToString(GetEffectInteger(eEffect, 0)) + "% Concealment" + (sMissChance == "" ? "" : " (" + sMissChance + ")"); + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + break; + } + case EFFECT_TYPE_SPELL_RESISTANCE_INCREASE: + case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: + { + string sModifier = GetModifierType(nEffectType, EFFECT_TYPE_SPELL_RESISTANCE_INCREASE, EFFECT_TYPE_SPELL_RESISTANCE_DECREASE); + sStats = sModifier + IntToString(GetEffectInteger(eEffect, 0)) + " Spell Resistance"; + break; + } + case EFFECT_TYPE_SPELL_FAILURE: + { + sStats = IntToString(GetEffectInteger(eEffect, 0)) + "% Spell Failure (Spell School: " + SpellSchoolToString(GetEffectInteger(eEffect, 1)) + ")"; + break; + } + case EFFECT_TYPE_INVISIBILITY: + { + int nInvisibilityType = GetEffectInteger(eEffect, 0); + if (nEffectIconID == EFFECT_ICON_INVISIBILITY) + bSkipDisplay = nInvisibilityType != INVISIBILITY_TYPE_NORMAL; + else if (nEffectIconID == EFFECT_ICON_IMPROVEDINVISIBILITY) + bSkipDisplay = nInvisibilityType != INVISIBILITY_TYPE_IMPROVED; + if (!bSkipDisplay) + { + sStats = (nInvisibilityType == INVISIBILITY_TYPE_IMPROVED ? "Improved " : "") + "Invisibility"; + sRacialTypeAlignment = GetVersusRacialTypeAndAlignment(GetEffectInteger(eEffect, 1), GetEffectInteger(eEffect, 2), GetEffectInteger(eEffect, 3)); + } + break; + } + case EFFECT_TYPE_HASTE: + { + sStats = "Hasted"; + } + } + if(!bSkipDisplay) + { + sText = sSpellName + " " + sDurationRemaining + (sStats == "" ? "" : " -> " + sStats + sRacialTypeAlignment); + if(sText != "") + { + jRow = CreateLabel(JsonArray(), " " + sText, "lbl_buff_info" + IntToString(nIndex), 700.0f, 10.0f, NUI_HALIGN_LEFT, NUI_VALIGN_TOP, 0.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 10.0; + object oSource = GetEffectCreator(eEffect); + if(GetIsObjectValid(oSource)) + { + sText = GetObjectType(oSource) ? GetName(oSource) : ""; + sText = " Creator: " + sText; + float fLength = IntToFloat(GetStringLength(sText) * 8); + jRow = CreateLabel(JsonArray(), sText, "lbl_buff_source" + IntToString(nIndex), fLength, 15.0f, NUI_HALIGN_LEFT, NUI_VALIGN_BOTTOM, 0.0); + if(oSource == oPlayer) + { + CreateButton(jRow, "Remove", "btn_remove_effect_" + IntToString(nEffectIndex++), 70.0f, 20.0f, 0.0); + jEffectID = JsonArrayInsert(jEffectID, JsonString(GetEffectLinkId(eEffect))); + fHeight += 20.0; + } + else fHeight += 15.0; + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + } + } + } + } + nIndex++; + eEffect = GetNextEffect(oPlayer); + } + float fScale = IntToFloat(GetPlayerDeviceProperty(oPlayer, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0; + float fX = IntToFloat(GetPlayerDeviceProperty(oPlayer, PLAYER_DEVICE_PROPERTY_GUI_WIDTH)); + fX = fX - (700.0 * fScale); + float fY = 50 * fScale; + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPlayer, jLayout, AI_EFFECT_ICON_NUI, "Effect Icon Menu", + fX, fY, 700.0, fHeight * fScale, FALSE, FALSE, FALSE, TRUE, FALSE, "0e_nui"); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oPlayer))); + jData = JsonArrayInsert(jData, JsonInt(nEffectIconID)); + jData = JsonArrayInsert(jData, jEffectID); + NuiSetUserData(oPlayer, nToken, jData); + NuiSetBind(oPlayer, nToken, "lbl_buff_name_event", JsonBool(TRUE)); + while(nIndex >= 0) + { + NuiSetBind(oPlayer, nToken, "lbl_buff_info" + IntToString(nIndex) + "_event", JsonBool(TRUE)); + NuiSetBind(oPlayer, nToken, "lbl_buff_source" + IntToString(nIndex) + "_event", JsonBool(TRUE)); + nIndex--; + } + while(nEffectIndex >= 0) + { + NuiSetBind(oPlayer, nToken, "btn_remove_effect_" + IntToString(nEffectIndex) + "_event", JsonBool(TRUE)); + NuiSetBind(oPlayer, nToken, "btn_remove_effect_" + IntToString(nEffectIndex), JsonInt(TRUE)); + nEffectIndex--; + } +} diff --git a/src/module/nss/0i_items.nss b/src/module/nss/0i_items.nss new file mode 100644 index 0000000..87d3ce7 --- /dev/null +++ b/src/module/nss/0i_items.nss @@ -0,0 +1,1243 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +Script Name: 0i_items +Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts for use with items. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +//#include "0i_main" +#include "0i_messages" +// Returns TRUE if oItem is a weapon. +int ai_GetIsWeapon(object oItem); +// Returns TRUE if oItem is a melee weapon. +int ai_GetIsMeleeWeapon(object oItem); +// Returns TRUE if oItem is a slashing weapon. +int ai_GetIsSlashingWeapon(object oItem); +// Returns TRUE if oItem is a piercing weapon. +int ai_GetIsPiercingWeapon(object oItem); +// Returns TRUE if oItem is a bludgeoning weapon. +int ai_GetIsBludgeoningWeapon(object oItem); +// Returns TRUE if oItem is an ammo. +int ai_GetIsAmmo(object oItem); +// Returns TRUE if oItem is a thrown weapon. +int ai_GetIsThrownWeapon(object oItem); +// Returns TRUE if oItem is able to be used single handed by oCreature. +int ai_GetIsSingleHandedWeapon(object oItem, object oCreature); +// Returns TRUE if oItem is a light weapon for oCreature. +int ai_GetIsLightWeapon(object oItem, object oCreature); +// Returns TRUE if oItem is able to be used two handed by oCreature. +int ai_GetIsTwoHandedWeapon(object oItem, object oCreature); +// Returns TRUE if oItem is a double weapon. +int ai_GetIsDoubleWeapon(object oItem); +// Returns TRUE if oCreature has a ranged weapon equiped and has ammo for it. +int ai_HasRangedWeaponWithAmmo(object oCreature); +// Returns TRUE if oItem is a ranged weapon. +int ai_GetIsRangeWeapon(object oItem); +// Returns the amount of damage the weapon oCreature is holding. +// nDamageAmount tells the function the amount of damage to return; +// 1 - Minimum, 2- Average, 3 Maximum. +// bMelee If it is not a melee weapon then return 0; +int ai_GetWeaponDamage(object oCreature, int nDamageAmount = 3, int bMelee = FALSE); +// Returns TRUE if oItem is a shield. +int ai_GetIsShield(object oItem); +// Returns the size of oItem using 1 = small to 6 = large. +int ai_GetItemSize(object oItem); +// Returns TRUE if the caller has a potion that is identified of nSpell. +int ai_CheckPotionIsIdentified(object oCreature, int nSpell); +// Returns an item from oCreature's inventory with sTag. +// bCheckEquiped will also look through the creatures equiped items. +// Returns OBJECT_INVALID if the items does not exist with sTag. +object ai_GetCreatureHasItem(object oCreature, string sTag, int bCheckEquiped = FALSE); +// Returns TRUE if oCreature can identify oItem based on the file SkillVsItemCost.2da +// Reports the findings to oPC unless oPC = OBJECT_INVALID. +// If the item can be identified by oCreature then it will be identified. +int ai_IdentifyItemVsKnowledge(object oCreature, object oItem, object oPC = OBJECT_INVALID); +// Identifies all items on oObject based on the file SkillVsItemCost.2da +// Reports the findings to oPC unless oPC = OBJECT_INVALID +// bIdentifyAll ignores the chart and does what it says! +void ai_IdentifyAllVsKnowledge(object oCreature, object oContainer, object oPC = OBJECT_INVALID); +// Will (Un)Identify all items on oCreature. +// If bIdentify is TRUE they will all be Identified, FALSE Unidentifies them. +void ai_SetIdentifyAllItems(object oCreature, int bIdentify = TRUE); +// Returns oWeapons attack bonus from either Enhancment or Attack bonus. +int ai_GetWeaponAtkBonus(object oWeapon); +// Returns oArmors armor bonus. +int ai_GetArmorBonus(object oArmor); +// Returns the maximum gold value that an item can have to be equiped. +int ai_GetMaxItemValueThatCanBeEquiped(int nLevel); +// Returns the minimum level that is required to equip this item. +int ai_GetMinimumEquipLevel(object oItem); +// Returns oCreatures total attack bonus with melee weapon (Mostly). +int ai_GetCreatureAttackBonus(object oCreature); +// Returns TRUE if oCreature can use oItem based on Class, Race, and Alignment +// restrictions. Also checks UseMagicDevice of oCreature. +int ai_CheckIfCanUseItem(object oCreature, object oItem); +// Returns TRUE if oCreature can use oItem due to feats. +int ai_GetIsProficientWith(object oCreature, object oItem); +// Gets the Average Damage on the weapon for Main and Off Hand to allow +// us to check which weapon is better for oCreature to equip. +// b2Handed set to TRUE returns only checks main avg damage. +// bOffHand set to TRUE returns the OffHand avg damage. +// if b2Handed & bOffHand are set to TRUE it returns main & offhand added together. +// if oOffWeapon is Set then it will return the Avg Damage assuming oItem is +// the Main weapon and oOffWeapon is in the Offhand. +float ai_GetMeleeWeaponAvgDmg(object oCreature, object oItem, int b2Handed = FALSE, int bOffHand = FALSE, object oOffWeapon = OBJECT_INVALID); +// Sets shield AC on the shield to allow us to check which shield is better +// for oCreature to equip. +int ai_SetShieldAC(object oCreature, object oItem); +// Returns TRUE if oItem has nItemPropertyType. +// nItemPropertySubType will not be used if its below 0. +int ai_GetHasItemProperty(object oItem, int nItemPropertyType, int nItemPropertySubType = -1); +// Returns the highest bonus Lock Picks needed to unlock nLockDC in oCreatures inventory. +object ai_GetBestPicks(object oCreature, int nLockDC); +// Removes all items from oCreature. +void ai_RemoveInventory(object oCreature); +// Copies all equiped and inventory items from oOldHenchman to oNewHenchman. +void ai_MoveInventory(object oOldHenchman, object oNewHenchman); +// Returns if oCreature is proficient with nBaseItem. +// PRC lets the creature use any weapon, but gives -4 penalty if not proficient. +int prc_IsProficient(object oCreature, int nBaseItem); + +int ai_GetIsWeapon(object oItem) +{ + int nType = GetBaseItemType(oItem); + int nWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", nType)); + if(nWeaponType) return TRUE; + return FALSE; +} +int ai_GetIsMeleeWeapon(object oItem) +{ + int nType = GetBaseItemType(oItem); + if(StringToInt(Get2DAString("baseitems", "WeaponType", nType)) > 0) + { + if(StringToInt(Get2DAString("baseitems", "RangedWeapon", nType)) == 0) return TRUE; + } + return FALSE; +} +int ai_GetIsSingleHandedWeapon(object oItem, object oCreature) +{ + if(!ai_GetIsMeleeWeapon(oItem)) return FALSE; + int nBaseItemType = GetBaseItemType(oItem); + // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType)); + // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nCreatureSize = GetCreatureSize(oCreature); + return nWeaponSize <= nCreatureSize; +} +int ai_GetIsLightWeapon(object oItem, object oCreature) +{ + if(!ai_GetIsMeleeWeapon(oItem)) return FALSE; + int nBaseItemType = GetBaseItemType(oItem); + // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType)); + // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nCreatureSize = GetCreatureSize(oCreature); + return nWeaponSize < nCreatureSize; +} +int ai_GetIsTwoHandedWeapon(object oItem, object oCreature) +{ + if(!ai_GetIsMeleeWeapon(oItem)) return FALSE; + int nBaseItemType = GetBaseItemType(oItem); + // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType)); + // Ranged weapons have a value greater than 0 in this field. So melee weapons have 0. + int nWeaponMelee = StringToInt(Get2DAString("baseitems", "RangedWeapon", nBaseItemType)); + // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nCreatureSize = GetCreatureSize(oCreature); + return (nWeaponMelee == 0 && nWeaponSize > nCreatureSize); +} +int ai_GetIsDoubleWeapon(object oItem) +{ + int iType = GetBaseItemType(oItem); + switch(iType) + { + case BASE_ITEM_DIREMACE: + case BASE_ITEM_DOUBLEAXE: + case BASE_ITEM_TWOBLADEDSWORD: return TRUE; + } + return FALSE; +} +int ai_GetIsSlashingWeapon(object oItem) +{ + int iBaseItemType = GetBaseItemType(oItem); + int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType)); + // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing. + return (iWeaponType == 3); +} +int ai_GetIsPiercingWeapon(object oItem) +{ + int iBaseItemType = GetBaseItemType(oItem); + int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType)); + // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing. + return (iWeaponType == 1); +} +int ai_GetIsBludgeoningWeapon(object oItem) +{ + int iBaseItemType = GetBaseItemType(oItem); + int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType)); + // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing. + return (iWeaponType == 2); +} +int ai_GetIsAmmo(object oItem) +{ + switch(GetBaseItemType(oItem)) + { + case BASE_ITEM_ARROW: return TRUE; + case BASE_ITEM_BOLT: return TRUE; + case BASE_ITEM_BULLET: return TRUE; + } + return FALSE; +} +int ai_GetIsThrownWeapon(object oItem) +{ + switch(GetBaseItemType(oItem)) + { + case BASE_ITEM_DART: return TRUE; + case BASE_ITEM_SHURIKEN: return TRUE; + case BASE_ITEM_THROWINGAXE: return TRUE; + } + return FALSE; +} +int ai_HasRangedWeaponWithAmmo(object oCreature) +{ + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + if(!GetWeaponRanged(oWeapon)) return FALSE; + int nAmmoType, nWeaponType = GetBaseItemType(oWeapon); + object oAmmo = OBJECT_INVALID; + if(nWeaponType == BASE_ITEM_LONGBOW || nWeaponType == BASE_ITEM_SHORTBOW) + { + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE; + if(GetItemInSlot(INVENTORY_SLOT_ARROWS, oCreature) != OBJECT_INVALID) return TRUE; + nAmmoType = BASE_ITEM_ARROW; + } + else if(nWeaponType == BASE_ITEM_LIGHTCROSSBOW || nWeaponType == BASE_ITEM_HEAVYCROSSBOW) + { + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE; + if(GetItemInSlot(INVENTORY_SLOT_BOLTS, oCreature) != OBJECT_INVALID) return TRUE; + nAmmoType = BASE_ITEM_BOLT; + } + else if(nWeaponType == BASE_ITEM_SLING) + { + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE; + if(GetItemInSlot(INVENTORY_SLOT_BULLETS, oCreature) != OBJECT_INVALID) return TRUE; + nAmmoType = BASE_ITEM_BULLET; + } + else if(nWeaponType == BASE_ITEM_THROWINGAXE) return TRUE; + else if(nWeaponType == BASE_ITEM_SHURIKEN) return TRUE; + else if(nWeaponType == BASE_ITEM_DART) return TRUE; + // They don't have any ammo in the slot, but do they have ammo in the inventory? + oAmmo = GetFirstItemInInventory(oCreature); + while(oAmmo != OBJECT_INVALID) + { + if(GetBaseItemType(oAmmo) == nAmmoType) + { + if(nAmmoType == BASE_ITEM_ARROW) ActionEquipItem(oAmmo, INVENTORY_SLOT_ARROWS); + else if(nAmmoType == BASE_ITEM_BOLT) ActionEquipItem(oAmmo, INVENTORY_SLOT_BOLTS); + else if(nAmmoType == BASE_ITEM_BULLET) ActionEquipItem(oAmmo, INVENTORY_SLOT_BULLETS); + return TRUE; + } + oAmmo = GetNextItemInInventory(oCreature); + } + //ai_Debug("0i_items", "254", "They are out of ammo!"); + return FALSE; +} +int ai_GetIsRangeWeapon(object oItem) +{ + switch(GetBaseItemType(oItem)) + { + case BASE_ITEM_DART: return TRUE; + case BASE_ITEM_HEAVYCROSSBOW: return TRUE; + case BASE_ITEM_LIGHTCROSSBOW: return TRUE; + case BASE_ITEM_LONGBOW: return TRUE; + case BASE_ITEM_SHORTBOW: return TRUE; + case BASE_ITEM_SHURIKEN: return TRUE; + case BASE_ITEM_SLING: return TRUE; + case BASE_ITEM_THROWINGAXE: return TRUE; + } + return FALSE; +} +int ai_GetIsFinesseWeapon(object oCreature, object oItem) +{ + switch(GetBaseItemType(oItem)) + { + case BASE_ITEM_DAGGER: return TRUE; + case BASE_ITEM_HANDAXE: return TRUE; + case BASE_ITEM_KAMA: return TRUE; + case BASE_ITEM_KUKRI: return TRUE; + case BASE_ITEM_LIGHTHAMMER: return TRUE; + case BASE_ITEM_LIGHTMACE: return TRUE; + case BASE_ITEM_RAPIER: + { + if(GetCreatureSize(oCreature) > CREATURE_SIZE_SMALL) return TRUE; + return FALSE; + } + case BASE_ITEM_SHORTSWORD: return TRUE; + case BASE_ITEM_SICKLE: return TRUE; + case BASE_ITEM_WHIP: return TRUE; + } + return FALSE; +} +int ai_GetWeaponDamage(object oCreature, int nDamageAmount = 3, int bMelee = FALSE) +{ + object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + if(bMelee && ai_GetIsRangeWeapon(oItem)) return 0; + int nWeaponDamage = GetLocalInt(oItem, "AI_WEAPON_DAMAGE"); + if(!nWeaponDamage) + { + if(ai_GetIsMeleeWeapon(oItem)) + { + nWeaponDamage = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(ai_GetIsTwoHandedWeapon(oItem, oCreature)) nWeaponDamage += nWeaponDamage / 2; + } + int nWeaponDice = StringToInt(Get2DAString("baseitems", "NumDice", GetBaseItemType(oItem))); + int nWeaponDie = StringToInt(Get2DAString("baseitems", "DieToRoll", GetBaseItemType(oItem))); + if(nDamageAmount == 1) + { + nWeaponDamage += nWeaponDice; + } + else if(nDamageAmount == 2) + { + nWeaponDamage += nWeaponDice * nWeaponDie / 2; + } + else + { + nWeaponDamage += nWeaponDice * nWeaponDie; + } + SetLocalInt(oItem, "AI_WEAPON_DAMAGE", nWeaponDamage); + } + return nWeaponDamage; +} +int ai_GetIsShield(object oItem) +{ + switch(GetBaseItemType(oItem)) + { + case BASE_ITEM_SMALLSHIELD: return TRUE; + case BASE_ITEM_LARGESHIELD: return TRUE; + case BASE_ITEM_TOWERSHIELD: return TRUE; + } + return FALSE; + } +int ai_GetItemSize(object oItem) +{ + int nBaseItemType = GetBaseItemType(oItem); + int nWidth = StringToInt(Get2DAString("baseitems", "InvSlotWidth", nBaseItemType)); + int nHeight = StringToInt(Get2DAString("baseitems", "InvSlotHeight", nBaseItemType)); + return nWidth + nHeight - 1; +} +int ai_CheckPotionIsIdentified(object oCreature, int nSpell) +{ + int nPotionSpell; + itemproperty ipPotion; + object oPotion = GetFirstItemInInventory(oCreature); + while(oPotion != OBJECT_INVALID) + { + if(GetIdentified(oPotion)) + { + ipPotion = GetFirstItemProperty(oPotion); + nPotionSpell = GetItemPropertySubType(ipPotion); + nPotionSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nPotionSpell)); + //ai_Debug("0i_talents", "318", "Potion ID'ed? nSpell: " + IntToString(nSpell) + " nPotionSpell: " + IntToString(nPotionSpell)); + if(nSpell == nPotionSpell) return TRUE; + } + oPotion = GetNextItemInInventory(oCreature); + } + return FALSE; +} +object ai_GetCreatureHasItem(object oCreature, string sTag, int bCheckEquiped = FALSE) +{ + // Cycle through the creatures unequiped items. + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetTag(oItem) == sTag) return oItem; + oItem = GetNextItemInInventory(oCreature); + } + // Should we check the creatures equiped items. + // If we have already found it then stop looking. + int nSlot = 0; + if(bCheckEquiped) + { + // Check all of the creatures slots(0 - 17). + while(nSlot <= 17) + { + oItem = GetItemInSlot(nSlot, oCreature); + if(GetTag(oItem) == sTag) return oItem; + nSlot ++; + } + } + return OBJECT_INVALID; +} +int ai_IdentifyItemVsKnowledge(object oCreature, object oItem, object oPC = OBJECT_INVALID) +{ + if(GetIdentified(oItem)) return FALSE; + int nKnowledge = GetSkillRank(SKILL_LORE, oCreature); + int nItemValue; // gold value of item + string sBaseName; + string sMaxValue = Get2DAString("SkillVsItemCost", "DeviceCostMax", nKnowledge); + int nMaxValue = StringToInt(sMaxValue); + // * Handle overflow(November 2003 - BK) + if(sMaxValue == "") nMaxValue = 0; + // Setting TRUE to get the true value of the item. + SetIdentified(oItem, TRUE); + nItemValue = GetGoldPieceValue(oItem); + if(nMaxValue <= nItemValue) + { + SetIdentified(oItem, FALSE); + if(oPC != OBJECT_INVALID) + { + sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem)))); + ai_SendMessages(GetName(oCreature) + " cannot identify " + sBaseName, AI_COLOR_RED, oPC); + } + } + else + { + if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " has identified " + GetName(oItem), AI_COLOR_GREEN, oPC); + return TRUE; + } + return FALSE; +} +void ai_IdentifyAllVsKnowledge(object oCreature, object oContainer, object oPC = OBJECT_INVALID) +{ + // SkillVsItemCost 2da starts 1 at 0 ... go figure! + int nKnowledge = GetSkillRank(SKILL_LORE, oCreature) - 1; + int nItemValue; // gold value of item + string sBaseName; + string sMaxValue = Get2DAString("SkillVsItemCost", "DeviceCostMax", nKnowledge); + int nMaxValue = StringToInt(sMaxValue); + // * Handle overflow(November 2003 - BK) + if(sMaxValue == "") nMaxValue = 0; + object oItem = GetFirstItemInInventory(oContainer); + while(oItem != OBJECT_INVALID) + { + if(!GetIdentified(oItem)) + { + // setting TRUE to get the true value of the item. + SetIdentified(oItem, TRUE); + nItemValue = GetGoldPieceValue(oItem); + if(nMaxValue < nItemValue) + { + SetIdentified(oItem, FALSE); + sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem)))); + if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " cannot identify " + sBaseName, AI_COLOR_RED, oPC); + } + else if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " has identified " + GetName(oItem), AI_COLOR_GREEN, oPC); + } + oItem = GetNextItemInInventory(oContainer); + } +} +void ai_SetIdentifyAllItems(object oCreature, int bIdentify = TRUE) +{ + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(!GetIdentified(oItem)) SetIdentified(oItem, bIdentify); + oItem = GetNextItemInInventory(oCreature); + } + int nSlot; + oItem = GetItemInSlot(nSlot, oCreature); + while(nSlot < 11) + { + if(!GetIdentified(oItem)) SetIdentified(oItem, bIdentify); + oItem = GetItemInSlot(++nSlot, oCreature); + } +} +int ai_GetWeaponAtkBonus(object oWeapon) +{ + int nCounter = 1, nPropertyType, nBonus; + // Get first property + itemproperty ipProperty = GetFirstItemProperty(oWeapon); + while(GetIsItemPropertyValid(ipProperty)) + { + // Check to see if the property type matches. + nPropertyType = GetItemPropertyType(ipProperty); + if(nPropertyType == 6/*ITEMPROPERTY_ENHANCEMENT*/ || + nPropertyType == 56/*ITEMPROPERTY_ATTACKBONUS*/) + { + nBonus += GetItemPropertyCostTableValue(ipProperty); + } + // Get the next property. + ipProperty = GetNextItemProperty(oWeapon); + } + //ai_Debug("0i_items", "438", GetName(oWeapon) + " attack bonus is " + IntToString(nBonus)); + return nBonus; +} +int ai_GetArmorBonus(object oArmor) +{ + int nTorsoValue = GetItemAppearance(oArmor, ITEM_APPR_TYPE_ARMOR_MODEL, ITEM_APPR_ARMOR_MODEL_TORSO); + //ai_Debug("0i_items", "444", "Armor Bonus: " + Get2DAString("parts_chest.2da", "ACBONUS", nTorsoValue)); + return StringToInt(Get2DAString("parts_chest", "ACBONUS", nTorsoValue)); +} +int ai_GetMaxItemValueThatCanBeEquiped(int nLevel) +{ + return StringToInt(Get2DAString("itemvalue", "MAXSINGLEITEMVALUE", nLevel - 1)); +} +int ai_GetMinimumEquipLevel(object oItem) +{ + int nIndex, nUnIdentified; + if(!GetIdentified(oItem)) + { + nUnIdentified = TRUE; + SetIdentified(oItem, TRUE); + } + int nGoldValue = GetGoldPieceValue(oItem); + if(nUnIdentified) SetIdentified(oItem, FALSE); + int n2daMaxRow = Get2DARowCount("itemvalue"); + while(nIndex < n2daMaxRow) + { + if(nGoldValue <= StringToInt(Get2DAString("itemvalue", "MAXSINGLEITEMVALUE", nIndex))) + { + return nIndex + 1; + } + nIndex++; + } + return nIndex; +} +int ai_GetCreatureAttackBonus(object oCreature) +{ + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature); + int nAtkBonus = GetBaseAttackBonus(oCreature); + if((GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) && ai_GetIsFinesseWeapon(oCreature, oWeapon)) || + ai_GetIsRangeWeapon(oWeapon)) + { + nAtkBonus += GetAbilityModifier(ABILITY_DEXTERITY, oCreature); + } + else nAtkBonus += GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(ai_GetIsMeleeWeapon(oWeapon)) nAtkBonus += ai_GetWeaponAtkBonus(oWeapon); + return nAtkBonus; + } +int ai_CheckUseMagicDevice(object oCreature, string sColumn, object oItem) +{ + if(!GetLocalInt(GetModule(), AI_RULE_ALLOW_UMD)) return FALSE; + int nUMD = GetSkillRank(SKILL_USE_MAGIC_DEVICE, oCreature); + //ai_Debug("0i_talents", "1600", GetName(oCreature) + " is check UMD: " + IntToString(nUMD)); + if(nUMD < 1) return FALSE; + int nDC, nIndex, nItemValue = GetGoldPieceValue(oItem); + while(nIndex < 55) + { + //ai_Debug("0i_talents", "1605", GetName(oItem) + " has a value of " + + // Get2DAString("skillvsitemcost", "DeviceCostMax", nIndex) + + // " nIndex: " + IntToString(nIndex)); + if(nItemValue < StringToInt(Get2DAString("skillvsitemcost", "DeviceCostMax", nIndex))) + { + //ai_Debug("0i_talents", "1610", "nUMD >= " + Get2DAString("skillvsitemcost", sColumn, nIndex)); + if(nUMD >= StringToInt(Get2DAString("skillvsitemcost", sColumn, nIndex))) return TRUE; + return FALSE; + } + nIndex++; + } + return FALSE; +} +int ai_CheckIfCanUseItem(object oCreature, object oItem) +{ + int bAlign, bClass, bRace, bAlignLimit, bClassLimit, bRaceLimit; + int nIprpSubType, nItemPropertyType; + // Check to see if this item is limited to a specific alignment, class, or race. + int nAlign1 = GetAlignmentLawChaos(oCreature); + int nAlign2 = GetAlignmentGoodEvil(oCreature); + int nRace = GetRacialType(oCreature); + //ai_Debug("0i_items", "615", "nAlign1: " + IntToString(nAlign1) + + // " nAlign2: " + IntToString(nAlign2) + " nRace: " + IntToString(nRace)); + itemproperty ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + nItemPropertyType = GetItemPropertyType(ipProp); + //ai_Debug("0i_items", "620", "ItempropertyType(62/63/64/65): " + IntToString(nItemPropertyType)); + if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_ALIGNMENT_GROUP) + { + bAlignLimit = TRUE; + // SubType is the group index for iprp_aligngrp.2da + nIprpSubType = GetItemPropertySubType(ipProp); + //ai_Debug("0i_items", "626", "nIprpSubType: " + IntToString(nIprpSubType)); + if(nIprpSubType == nAlign1 || nIprpSubType == nAlign2) bAlign = TRUE; + } + else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_SPECIFIC_ALIGNMENT) + { + bAlignLimit = TRUE; + // SubType is the alignment index for iprp_alignment.2da + nIprpSubType = GetItemPropertySubType(ipProp); + //ai_Debug("0i_items", "634", "nIprpSubType: " + IntToString(nIprpSubType)); + if(nIprpSubType == 0 && nAlign1 == 2 && nAlign2 == 4) bAlign = TRUE; + else if(nIprpSubType == 1 && nAlign1 == 2 && nAlign2 == 1) bAlign = TRUE; + else if(nIprpSubType == 2 && nAlign1 == 2 && nAlign2 == 5) bAlign = TRUE; + else if(nIprpSubType == 3 && nAlign1 == 1 && nAlign2 == 4) bAlign = TRUE; + else if(nIprpSubType == 4 && nAlign1 == 1 && nAlign2 == 1) bAlign = TRUE; + else if(nIprpSubType == 5 && nAlign1 == 1 && nAlign2 == 5) bAlign = TRUE; + else if(nIprpSubType == 6 && nAlign1 == 3 && nAlign2 == 4) bAlign = TRUE; + else if(nIprpSubType == 7 && nAlign1 == 3 && nAlign2 == 1) bAlign = TRUE; + else if(nIprpSubType == 8 && nAlign1 == 3 && nAlign2 == 5) bAlign = TRUE; + } + else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_CLASS) + { + bClassLimit = TRUE; + // SubType is the class index for classes.2da + nIprpSubType = GetItemPropertySubType(ipProp); + //ai_Debug("0i_items", "650", "nIprpSubType: " + IntToString(nIprpSubType)); + int nClassPosition = 1; + int nClass = GetClassByPosition(nClassPosition, oCreature); + while(nClassPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + if(nIprpSubType == nClass) bClass = TRUE; + nClass = GetClassByPosition(++nClassPosition, oCreature); + } + } + else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_RACIAL_TYPE) + { + bRaceLimit = TRUE; + // SubType is the race index for racialtypes.2da + nIprpSubType = GetItemPropertySubType(ipProp); + //ai_Debug("0i_items", "664", "nIprpSubType: " + IntToString(nIprpSubType)); + if(nIprpSubType == nRace) bRace = TRUE; + } + ipProp = GetNextItemProperty(oItem); + } + //ai_Debug("0i_items", "669", "bAlignLimit: " + IntToString(bAlignLimit) + " bAlign: " + IntToString(bAlign) + + // " bClassLimit: " + IntToString(bClassLimit) + " bClass: " + IntToString(bClass) + + // " bRaceLimit: " + IntToString(bRaceLimit) + " bRace: " + IntToString(bRace)); + if(bClassLimit && !bClass && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Class", oItem)) return FALSE; + if(bRaceLimit && !bRace && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Race", oItem)) return FALSE; + if(bAlignLimit && !bAlign && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Align", oItem)) return FALSE; + return TRUE; +} +int ai_GetIsProficientWith(object oCreature, object oItem) +{ + int nWeaponType = GetBaseItemType(oItem); + // In the PRC you can equip any weapon. + if(GetLocalInt(GetModule(), AI_USING_PRC)) return TRUE; + int nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat0", nWeaponType)); + // If it is 0 then it doesn't require a feat or we are at the end of the + // feat requirements. + if(nFeat == 0) return TRUE; + if(GetHasFeat(nFeat, oCreature)) return TRUE; + nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat1", nWeaponType)); + if(nFeat == 0) return FALSE; + if(GetHasFeat(nFeat, oCreature)) return TRUE; + nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat2", nWeaponType)); + if(nFeat == 0) return FALSE; + if(GetHasFeat(nFeat, oCreature)) return TRUE; + nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat3", nWeaponType)); + if(nFeat == 0) return FALSE; + if(GetHasFeat(nFeat, oCreature)) return TRUE; + nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat4", nWeaponType)); + if(nFeat == 0) return FALSE; + if(GetHasFeat(nFeat, oCreature)) return TRUE; + return FALSE; +} +float ai_GetMeleeWeaponAvgDmg(object oCreature, object oItem, int b2Handed = FALSE, int bOffHand = FALSE, object oOffWeapon = OBJECT_INVALID) +{ + // Has this weapon already been calculated for this creature? + if(oCreature == GetLocalObject(oItem, "AI_CREATURE_POSSESSION")) + { + // Return the Main weapons Avg Damage while using a weapon in the off hand. + if(oOffWeapon != OBJECT_INVALID) + { + // We recalculate all OffWeapon avg damage unless its a double weapon. + if(oOffWeapon == oItem) + { + float fMain2WDmg = GetLocalFloat(oItem, "AI_MAIN_2W_HAND_AVG_DMG"); + // If they passed that this is a 2handed weapon then return the total + // Avg Dmg for oItem. Used for double weapons. + if(b2Handed) + { + fMain2WDmg += ai_GetMeleeWeaponAvgDmg(oCreature, oItem, FALSE, TRUE); + } + if(AI_DEBUG) ai_Debug("0i_items", "611", GetName(oItem) + " avg dmg with Offhand weapon (" + GetName(oOffWeapon) + ") " + FloatToString(fMain2WDmg, 0, 2)); + return fMain2WDmg; + } + } + // Return the avg dmg for oItem assuming it is in the OffHand. + else if(bOffHand) + { + float fOffHandDmg = GetLocalFloat(oItem, "AI_OFFHAND_AVG_DMG"); + if(AI_DEBUG) ai_Debug("0i_items", "618", GetName(oItem) + " fOffHandAvgDmg: " + FloatToString(fOffHandDmg, 0, 2)); + return fOffHandDmg; + } + // If we get here then Return the avg dmg for oItem assuming its in the main hand. + else + { + float fMainDmg = GetLocalFloat(oItem, "AI_AVG_DMG"); + if(AI_DEBUG)ai_Debug("0i_items", "623", GetName(oItem) + " fMainDmg: " + FloatToString(fMainDmg, 0, 2)); + return fMainDmg; + } + } + // Set the creature to this item that we are calculationg the avg damages for. + SetLocalObject(oItem, "AI_CREATURE_POSSESSION", oCreature); + int nItemType = GetBaseItemType(oItem); + // Figure average damage for one attack, or two with two weapons. + // We are keeping it simple to reduce time and checks. + // Get the weapons base stats. + int nMinDmg = StringToInt(Get2DAString("baseitems", "NumDice", nItemType)); + int nMaxDmg = nMinDmg * StringToInt(Get2DAString("baseitems", "DieToRoll", nItemType)); + int nThreat = StringToInt(Get2DAString("baseitems", "CritThreat", nItemType)); + int nMultiplier = StringToInt(Get2DAString("baseitems", "CritHitMult", nItemType)); + int nIndex, nBonusMinDmg, nBonusMaxDmg, nItemPropertyType, nNumDice; + // We set ToHit to 10 for a 50% chance to hit without modifiers. + float fCritBonusDmg, fToHit = 10.0; + if(GetLocalInt(GetModule(), AI_USING_PRC)) + { + if(!prc_IsProficient(oCreature, nItemType)) fToHit -= 4.0; + } + // Check oCreature's feats. + if(GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) && + ai_GetIsLightWeapon(oItem, oCreature)) + { + // Add Dexterity modifier to the Attack bonus. + nIndex = GetAbilityModifier(ABILITY_DEXTERITY, oCreature); + } + else + { + // Add Strength modifier to the attack bonus. + nIndex = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + // Add 1/2 strength modifier to damage for 2handed weapons, but not Double weapons. + if(b2Handed && !bOffHand) + { + nMinDmg += nIndex / 2; + nMaxDmg += nIndex / 2; + } + } + fToHit += nIndex; + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponFocusFeat", nItemType)), oCreature, TRUE)) + { + fToHit += 1.0; + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponSpecializationFeat", nItemType)), oCreature, TRUE)) + { + nMinDmg += 2; + nMaxDmg += 2; + } + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponFocusFeat", nItemType)), oCreature, TRUE)) + { + fToHit += 2.0; + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponSpecializationFeat", nItemType)), oCreature, TRUE)) + { + nMinDmg += 4; + nMaxDmg += 4; + } + } + } + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponImprovedCriticalFeat", nItemType)), oCreature, TRUE)) + { + nMultiplier += nMultiplier; + if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponOverwhelmingCriticalFeat", nItemType)), oCreature, TRUE)) + { + if(nMultiplier > 3) fCritBonusDmg = 10.5; + else if(nMultiplier == 3) fCritBonusDmg = 7.0; + else fCritBonusDmg = 3.5; + } + } + // Check oItem's properties. + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + nItemPropertyType = GetItemPropertyType(ipProperty); + if(nItemPropertyType == ITEM_PROPERTY_ENHANCEMENT_BONUS) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nBonusMinDmg += nIndex; + nBonusMaxDmg += nIndex; + fToHit += IntToFloat(nIndex); + } + else if(nItemPropertyType == ITEM_PROPERTY_DAMAGE_BONUS) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nNumDice = StringToInt(Get2DAString("iprp_damagecost", "NumDice", nIndex)); + nBonusMinDmg += nNumDice; + nBonusMaxDmg += nNumDice * StringToInt(Get2DAString("iprp_damagecost", "Die", nIndex)); + } + else if(nItemPropertyType == ITEM_PROPERTY_ATTACK_BONUS) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + fToHit += IntToFloat(nIndex); + } + else if(nItemPropertyType == ITEM_PROPERTY_KEEN) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nMultiplier += nMultiplier; + } + else if(nItemPropertyType == ITEM_PROPERTY_HASTE) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nMinDmg += nMinDmg; + nMaxDmg += nMaxDmg; + nBonusMinDmg += nBonusMinDmg; + nBonusMaxDmg += nBonusMaxDmg; + nMultiplier += nMultiplier; + } + else if(nItemPropertyType == ITEM_PROPERTY_MASSIVE_CRITICALS) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nNumDice = StringToInt(Get2DAString("iprp_damagecost", "NumDice", nIndex)); + fCritBonusDmg += IntToFloat(nNumDice) + IntToFloat(nNumDice * StringToInt(Get2DAString("iprp_damagecost", "Die", nIndex))) / 2.0; + } + else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nBonusMinDmg -= nIndex; + nBonusMaxDmg -= nIndex; + fToHit -= IntToFloat(nIndex); + } + else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + fToHit -= IntToFloat(nIndex); + } + else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_DAMAGE) + { + nIndex = GetItemPropertyCostTableValue(ipProperty); + nBonusMinDmg -= nIndex; + nBonusMaxDmg -= nIndex; + } + else if(nItemPropertyType == ITEM_PROPERTY_NO_DAMAGE) + { + // A weapon always does a minimum of 1 pnt of damage. + nMinDmg = 1; + nMaxDmg = 1; + } + ipProperty = GetNextItemProperty(oItem); + } + float fAvgDmg = IntToFloat(nMinDmg + nMaxDmg + nBonusMinDmg + nBonusMaxDmg) / 2; + // Set value for Offhand chance to hit. + float fOffHandToHit = fToHit - 10.0; + float fOffHandAvgDmg = fAvgDmg; + // Set value for Main hand chance to hit with a weapon in Off hand. + float fMain2HandToHit = fToHit - 6.0; + float fMain2HandAvgDmg = fAvgDmg; + // Calculate the avg dmg for oItem used in the main hand with no Off hand weapon. + fToHit = fToHit / 20.0; + float fThreatChance = (IntToFloat(nThreat) / 20.0) * fToHit; + fAvgDmg = (fAvgDmg * fToHit) + ((fAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance); + SetLocalFloat(oItem, "AI_AVG_DMG", fAvgDmg); + if(AI_DEBUG) ai_Debug("0i_items", "768", GetName(oItem) + " fSingleAvgDmg: " + FloatToString(fAvgDmg, 0, 2)); + if(!b2Handed || (b2Handed && oOffWeapon != OBJECT_INVALID)) + { + // Calculate chance to hit based on two weapon feats and main hand vs off hand. + if(GetHasFeat(374/*Dual_Wield*/, oCreature)) + { + if(ai_GetArmorBonus(GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature)) < 4) + { + fMain2HandToHit += 2.0; + fOffHandToHit += 6.0; + } + } + else + { + if(GetHasFeat(FEAT_AMBIDEXTERITY, oCreature)) fOffHandToHit += 4.0; + if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oCreature)) + { + fMain2HandToHit += 2.0; + fOffHandToHit += 2.0; + } + } + if(ai_GetIsLightWeapon(oItem, oCreature)) fOffHandToHit += 2.0; + if(oOffWeapon != OBJECT_INVALID && + (ai_GetIsLightWeapon(oOffWeapon, oCreature) || ai_GetIsDoubleWeapon(oItem))) + { + fMain2HandToHit += 2.0; + } + // Calculate the avg dmg for oItem used in the main hand with an off hand weapon. + fMain2HandToHit = fMain2HandToHit / 20.0; + fThreatChance = (IntToFloat(nThreat) / 20.0) * fMain2HandToHit; + fMain2HandAvgDmg = (fMain2HandAvgDmg * fMain2HandToHit) + ((fMain2HandAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance); + SetLocalFloat(oItem, "AI_MAIN_2W_HAND_AVG_DMG", fMain2HandAvgDmg); + if(AI_DEBUG) ai_Debug("0i_items", "768", GetName(oItem) + " fMain2HandAvgDmg: " + FloatToString(fMain2HandAvgDmg, 0, 2)); + // Calculate the avg dmg for oItem used in the off hand. + fOffHandToHit = fOffHandToHit / 20.0; + fThreatChance = (IntToFloat(nThreat) / 20.0) * fOffHandToHit; + fOffHandAvgDmg = (fOffHandAvgDmg * fOffHandToHit) + ((fOffHandAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance); + SetLocalFloat(oItem, "AI_OFFHAND_AVG_DMG", fOffHandAvgDmg); + if(AI_DEBUG) ai_Debug("0i_items", "790", GetName(oItem) + " fOffHandAvgDmg: " + FloatToString(fOffHandAvgDmg, 0, 2)); + // Return the correct value based on params passed. + if(oOffWeapon != OBJECT_INVALID) + { + // This is used only for double weapons! Must pass b2Handed = TRUE and + // oOffWeapon = the double weapon that was passes as oItem. + if(b2Handed) return fMain2HandAvgDmg + fOffHandAvgDmg; + return fMain2HandAvgDmg; + } + if(bOffHand) return fOffHandAvgDmg; + } + return fAvgDmg; +} +int ai_SetShieldAC(object oCreature, object oItem) +{ + if(oCreature == GetLocalObject(oItem, "AI_CREATURE_POSSESSION")) + { + return GetLocalInt(oItem, "AI_SHIELD_AC"); + } + // Set the creature who has this item for setting the power of. + SetLocalObject(oItem, "AI_CREATURE_POSSESSION", oCreature); + int nItemType = GetBaseItemType(oItem); + int nAC, nItemPropertyType; + if(nItemType == BASE_ITEM_SMALLSHIELD) nAC = 1; + else if(nItemType == BASE_ITEM_LARGESHIELD) nAC = 2; + else if(nItemType == BASE_ITEM_TOWERSHIELD) nAC = 3; + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + nItemPropertyType = GetItemPropertyType(ipProperty); + if(nItemPropertyType == ITEM_PROPERTY_AC_BONUS) + { + nAC += GetItemPropertyCostTableValue(ipProperty); + } + else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_AC) + { + nAC -= GetItemPropertyCostTableValue(ipProperty); + } + else if(nItemPropertyType == ITEM_PROPERTY_HASTE) + { + nAC += 4; + } + ipProperty = GetNextItemProperty(oItem); + } + SetLocalInt(oItem, "AI_SHIELD_AC", nAC); + if(AI_DEBUG) ai_Debug("0i_items", "718", GetName(oItem) + " nAC: " + IntToString(nAC)); + return nAC; +} +int ai_GetHasItemProperty(object oItem, int nItemPropertyType, int nItemPropertySubType = -1) +{ + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(GetItemPropertyType(ipProperty) == nItemPropertyType) + { + if(nItemPropertySubType > -1) + { + if(GetItemPropertySubType(ipProperty) == nItemPropertySubType) return TRUE; + } + else return TRUE; + } + ipProperty = GetNextItemProperty(oItem); + } + return FALSE; +} +object ai_GetBestPicks(object oCreature, int nLockDC) +{ + int nSkill = GetSkillRank(SKILL_OPEN_LOCK, oCreature); + int nBonus, nBestBonus = 99, nNeededBonus = nLockDC - nSkill - 20; + //ai_Debug("0i_items", "651", "nNeededBonus: " + IntToString(nNeededBonus)); + // We don't need to use any picks! + if(nNeededBonus < 1) return OBJECT_INVALID; + object oBestItem = OBJECT_INVALID; + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetBaseItemType(oItem) == BASE_ITEM_THIEVESTOOLS) + { + // Get the tools bonus. + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_THIEVES_TOOLS) + { + nBonus = GetItemPropertyCostTableValue(ipProperty); + if(nBonus >= nNeededBonus && nBonus < nBestBonus) + { + nBestBonus = nBonus; + oBestItem = oItem; + SetLocalInt(oBestItem, "AI_BONUS", nBestBonus); + break; + } + } + ipProperty = GetNextItemProperty(oItem); + } + } + oItem = GetNextItemInInventory(oCreature); + } + return oBestItem; +} +void ai_RemoveInventory(object oCreature) +{ + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + DestroyObject(oItem); + oItem = GetNextItemInInventory(oCreature); + } + int nIndex; + for(nIndex = 0; nIndex <= 13; nIndex++) + { + oItem = GetItemInSlot(nIndex, oCreature); + DestroyObject(oItem); + } +} +void ai_MoveInventory(object oOldHenchman, object oNewHenchman) +{ + // Move all inventory items. + object oItem = GetFirstItemInInventory(oOldHenchman); + while(oItem != OBJECT_INVALID) + { + CopyItem(oItem, oNewHenchman, TRUE); + oItem = GetNextItemInInventory(oOldHenchman); + } + // Move all equiped items and equip on oNewHenchman. + int nIndex; + object oNewItem; + for(nIndex = 0; nIndex <= 13; nIndex++) + { + oItem = GetItemInSlot(nIndex, oOldHenchman); + if(oItem != OBJECT_INVALID) + { + oNewItem = CopyItem(oItem, oNewHenchman, TRUE); + if(!GetIdentified(oNewItem)) SetIdentified(oNewItem, TRUE); + ActionEquipItem(oNewItem, nIndex); + } + } +} +int prc_IsProficient(object oCreature, int nBaseItem) +{ + switch(nBaseItem) + { + //special case: counts as simple for chitine + case BASE_ITEM_SHORTSWORD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature) + || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + && GetRacialType(oCreature) == 76/*RACIAL_TYPE_CHITINE*/) + || GetHasFeat(7901/*FEAT_WEAPON_PROFICIENCY_SHORTSWORD*/, oCreature); + + case BASE_ITEM_LONGSWORD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature) + || GetHasFeat(7902/*FEAT_WEAPON_PROFICIENCY_LONGSWORD*/, oCreature); + + case BASE_ITEM_BATTLEAXE: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + && GetRacialType(oCreature) == 216/*RACIAL_TYPE_GNOLL*/) + || GetHasFeat(7903/*FEAT_WEAPON_PROFICIENCY_BATTLEAXE*/, oCreature); + + case BASE_ITEM_BASTARDSWORD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature) + || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature) + || GetHasFeat(7904/*FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD*/, oCreature); + + case BASE_ITEM_LIGHTFLAIL: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(7905/*FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL*/, oCreature); + + case BASE_ITEM_WARHAMMER: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(7906/*FEAT_WEAPON_PROFICIENCY_WARHAMMER*/, oCreature); + + case BASE_ITEM_LONGBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature) + || GetHasFeat(7907/*FEAT_WEAPON_PROFICIENCY_LONGBOW*/, oCreature); + + case BASE_ITEM_LIGHTMACE: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(7908/*FEAT_WEAPON_PROFICIENCY_LIGHT_MACE*/, oCreature); + + case BASE_ITEM_HALBERD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(7909/*FEAT_WEAPON_PROFICIENCY_HALBERD*/, oCreature); + + case BASE_ITEM_SHORTBOW: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature) + || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + && GetRacialType(oCreature) == 216/*RACIAL_TYPE_GNOLL*/) + || GetHasFeat(7910/*FEAT_WEAPON_PROFICIENCY_SHORTBOW*/, oCreature); + + case BASE_ITEM_TWOBLADEDSWORD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature) + || GetHasFeat(7911/*FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD*/, oCreature); + + case BASE_ITEM_GREATSWORD: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(7912/*FEAT_WEAPON_PROFICIENCY_GREATSWORD*/, oCreature); + + case BASE_ITEM_GREATAXE: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(7913/*FEAT_WEAPON_PROFICIENCY_GREATAXE*/, oCreature); + + case BASE_ITEM_DART: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature) + || GetHasFeat(7914/*FEAT_WEAPON_PROFICIENCY_DART*/, oCreature); + + case BASE_ITEM_DIREMACE: + return GetHasFeat(7915/*FEAT_WEAPON_PROFICIENCY_DIRE_MACE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_DOUBLEAXE: + return GetHasFeat(7916/*FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_HEAVYFLAIL: + return GetHasFeat(7917/*FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case BASE_ITEM_LIGHTHAMMER: + return GetHasFeat(7918/*FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case BASE_ITEM_HANDAXE: + return GetHasFeat(7919/*FEAT_WEAPON_PROFICIENCY_HANDAXE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature); + + case BASE_ITEM_KAMA: + return GetHasFeat(7920/*FEAT_WEAPON_PROFICIENCY_KAMA*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_KATANA: + return GetHasFeat(7921/*FEAT_WEAPON_PROFICIENCY_KATANA*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_KUKRI: + return GetHasFeat(7922/*FEAT_WEAPON_PROFICIENCY_KUKRI*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_MORNINGSTAR: + return GetHasFeat(7923/*FEAT_WEAPON_PROFICIENCY_MORNINGSTAR*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature); + + case BASE_ITEM_QUARTERSTAFF: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oCreature); + + case BASE_ITEM_RAPIER: + return GetHasFeat(7924/*FEAT_WEAPON_PROFICIENCY_RAPIER*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature); + + case BASE_ITEM_SCIMITAR: + return GetHasFeat(7925/*FEAT_WEAPON_PROFICIENCY_SCIMITAR*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature); + + case BASE_ITEM_SCYTHE: + return GetHasFeat(7926/*FEAT_WEAPON_PROFICIENCY_SCYTHE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case BASE_ITEM_SHORTSPEAR: + return GetHasFeat(7927/*FEAT_WEAPON_PROFICIENCY_SHORTSPEAR*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature); + + case BASE_ITEM_SHURIKEN: + return GetHasFeat(7928/*FEAT_WEAPON_PROFICIENCY_SHURIKEN*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature); + + case BASE_ITEM_SICKLE: + return GetHasFeat(7929/*FEAT_WEAPON_PROFICIENCY_SICKLE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature); + + case BASE_ITEM_SLING: + return GetHasFeat(7930/*FEAT_WEAPON_PROFICIENCY_SLING*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature); + + case BASE_ITEM_THROWINGAXE: + return GetHasFeat(7931/*FEAT_WEAPON_PROFICIENCY_THROWING_AXE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature); + + case BASE_ITEM_CSLASHWEAPON: + case BASE_ITEM_CPIERCWEAPON: + case BASE_ITEM_CBLUDGWEAPON: + case BASE_ITEM_CSLSHPRCWEAP: + return GetHasFeat(FEAT_WEAPON_PROFICIENCY_CREATURE, oCreature); + + case BASE_ITEM_TRIDENT: + return GetHasFeat(7932/*FEAT_WEAPON_PROFICIENCY_TRIDENT*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature); + + case 124://BASE_ITEM_DOUBLE_SCIMITAR: + return GetHasFeat(7948/*FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case 119://BASE_ITEM_FALCHION: + return GetHasFeat(7943/*FEAT_WEAPON_PROFICIENCY_FALCHION*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case 125://BASE_ITEM_GOAD: + return GetHasFeat(7949/*FEAT_WEAPON_PROFICIENCY_GOAD*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature); + + case 122://BASE_ITEM_HEAVY_MACE: + return GetHasFeat(7946/*FEAT_WEAPON_PROFICIENCY_HEAVY_MACE*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature); + + case 115://BASE_ITEM_HEAVY_PICK: + return GetHasFeat(7939/*FEAT_WEAPON_PROFICIENCY_HEAVY_PICK*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case 116://BASE_ITEM_LIGHT_PICK: + return GetHasFeat(7940/*FEAT_WEAPON_PROFICIENCY_LIGHT_PICK*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case 121://BASE_ITEM_KATAR: + return GetHasFeat(7945/*FEAT_WEAPON_PROFICIENCY_KATAR*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case 123://BASE_ITEM_MAUL: + return GetHasFeat(7947/*FEAT_WEAPON_PROFICIENCY_MAUL*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + case 118://BASE_ITEM_NUNCHAKU: + return GetHasFeat(7942/*FEAT_WEAPON_PROFICIENCY_NUNCHAKU*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case 117://BASE_ITEM_SAI: + return GetHasFeat(7941/*FEAT_WEAPON_PROFICIENCY_SAI*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case 120://BASE_ITEM_SAP: + return GetHasFeat(7944/*FEAT_WEAPON_PROFICIENCY_SAP*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature); + + //special case: counts as martial for dwarves + case BASE_ITEM_DWARVENWARAXE: + return GetHasFeat(7933/*FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE*/, oCreature) + || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature) + && GetHasFeat(4710/*FEAT_DWARVEN*/, oCreature)) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + + case BASE_ITEM_WHIP: + return GetHasFeat(7934/*FEAT_WEAPON_PROFICIENCY_WHIP*/, oCreature) + || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature); + } + return TRUE; +} +int ai_GetItemUses(object oItem, int nItemPropertySubType) +{ + int nUses; + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_HEALERS_KIT) return GetItemStackSize(oItem); + if(nItemPropertySubType > -1) + { + if(GetItemPropertySubType(ipProperty) == nItemPropertySubType) + { + // Get how they use the item (charges or uses per day). + nUses = GetItemPropertyCostTableValue(ipProperty); + if(nUses == 1) return GetItemStackSize(oItem); + else if(nUses > 1 && nUses < 7) return GetItemCharges(oItem); + else if(nUses == 7 || nUses == 13) return 999; + else if(nUses > 7 && nUses < 13) return GetItemPropertyUsesPerDayRemaining(oItem, ipProperty); + } + } + else return TRUE; + ipProperty = GetNextItemProperty(oItem); + } + return FALSE; +} + diff --git a/src/module/nss/0i_main.nss b/src/module/nss/0i_main.nss new file mode 100644 index 0000000..a0a4674 --- /dev/null +++ b/src/module/nss/0i_main.nss @@ -0,0 +1,1328 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_main +//////////////////////////////////////////////////////////////////////////////// + Include script for handling main/basic functions not defined by other includes. + + Database structure: Json with indexes. + name (string) - The associatetype to link the data. "pc", "familiar", etc. + modes (jsonarray) - 0-aimodes (int), 1-magicmodes (int) + buttons (jsonarray) - 0-widgetbuttons (int), 1-aibuttons (int) + aidata (jsonarray) - 0-difficulty (int), 1-healoutcombat (int), 2-healincombat (int), + 3-lootrange (float), 4-lockrange (float), 5-traprange (float), + 6-Follow range (float). + lootfilters (jsonarray) - 0-maxweight (int), 1-lootfilters (int), + Item filters in min gold json array; 2-plot, 3-armor, 4-belts, 5-boots, + 6-cloaks, 7-gems, 8-gloves, 9-headgear, 10-jewelry, 11-misc, 12-potions, + 13-scrolls, 14-shields, 15-wands, 16-weapons, 17-arrow, 18-bolt, 19-bullet. + plugins (jsonarray) - 0+ (string). * Only used in the "pc" data. + location (jsonobject) - geometry (json), used in widgets for pc and associates. +*/////////////////////////////////////////////////////////////////////////////// +const string AI_TABLE = "PEPS_TABLE"; +const string AI_CAMPAIGN_DATABASE = "peps_database"; +const string AI_DM_TABLE = "DM_TABLE"; +#include "0i_constants" +#include "0i_messages" +// Sets PEPS RULES from the database to the module. +// Creates default rules if they do not exist. +void ai_SetAIRules(); +// Returns TRUE if oCreature is controlled by a player. +int ai_GetIsCharacter(object oCreature); +// Returns TRUE if oCreature is controlled by a dungeon master. +int ai_GetIsDungeonMaster(object oCreature); +// Returns the Player of oAssociate even if oAssociate is the player. +// If there is no player associated with oAssociate then it returns OBJECT_INVALID. +object ai_GetPlayerMaster(object oAssociate); +// Returns the percentage of hit points oCreature has left. +int ai_GetPercHPLoss(object oCreature); +// Returns a rolled result from sDice string. +// Example: "1d6" will be 1-6 or "3d6" will be 3-18 or 1d6+5 will be 6-11. +int ai_RollDiceString(string sDice); +// Returns the int number of a encoded 0x00000000 hex number from a string. +int ai_HexStringToInt(string sString); +// Returns cosine of the angle between oObject1 and oObject2 +float ai_GetCosAngleBetween(object oObject1, object oObject2); +// Returns a string from sString with only characters in sLegal. +// Used to remove illegal characters for databases. +string ai_RemoveIllegalCharacters(string sString, string sLegal = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); +// Returns the total levels of oCreature. +int ai_GetCharacterLevels(object oCreature); +// Returns a string where sFind is replaced in any occurrence of sSource with sReplace. +string ai_StringReplaceText(string sSource, string sFind, string sReplace); +// Returns a string of characters between the nIndex of predefined markers of +// sSeperator in sText. +// nIndex is the number of the data we are searching for in the array. +// A 0 nIndex is the first item in the text array. +// sSeperator is the character that seperates the array(Usefull for Multiple arrays). +string ai_GetStringArray(string sText, int nIndex, string sSeperator = ":"); +// Returns a string of characters between the nIndex of predefined markers of +// sSeperator in sText where sField has been set. +// sText is the text holding the array. +// nIndex is the array number in the data we are searching for. +// A 0 nIndex is the first item in the text array. +// sField is the field of characters to replace that index. +// sSeperator is the character that seperates the array(Usefull for Multiple arrays). +string ai_SetStringArray(string sText, int nIndex, string sField, string sSeperator = ":"); +// Returns the number of magical properties oItem has. +int ai_GetNumberOfProperties(object oItem); +// Checks if the campaign database table has been created and initialized. +void ai_CheckCampaignDataAndInitialize(); +// Checks if the dm database table and data has been created and initialized of oDM. +void ai_CheckDMDataAndInitialize(object oDM); +// Sets json to a campaign database. +void ai_SetCampaignDbJson(string sDataField, json jData, string sName = "PEPS_DATA", string sTable = AI_TABLE); +// Gets json from a campaign database. +json ai_GetCampaignDbJson(string sDataField, string sName = "PEPS_DATA", string sTable = AI_TABLE); +// Checks if oMaster has the Table created for Associate data. +// If no table found then the table is created and then initialized. +void ai_CheckAssociateDataAndInitialize(object oPlayer, string sAssociateType); +// Returns the associatetype int string format for oAssociate. +// They are pc, familar, companion, summons, henchman is the henchmans tag +string ai_GetAssociateType(object oPlayer, object oAssociate); +// Sets nData to sDataField for sAssociateType that is on oPlayer. +// sDataField can be modes, magicmodes, lootmodes, widgetbuttons, aibuttons, magic, +// healoutcombat, healincombat, mingold*. +void ai_SetAssociateDbInt(object oPlayer, string sAssociateType, string sDataField, int nData, string sTable = AI_TABLE); +// Returns nData from sDataField for sAssociateType that is on oPlayer. +// sDataField can be modes, magicmodes, lootmodes, widgetbuttons, aibuttons, magic, +// healoutcombat, healincombat, mingold*. +int ai_GetAssociateDbInt(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE); +// Sets fData to sDataField for sAssociateType that is on oPlayer. +// sDataField can be lootrange, lockrange, traprange. +void ai_SetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, float fData, string sTable = AI_TABLE); +// Returns fData from sDataField for sAssociateType that is on oPlayer. +// sDataField can be lootrange, lockrange, traprange. +float ai_GetAssociateDbFloat(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE); +// sDataField should be one of the data fields for that table. +// jData is the json data to be saved. +void ai_SetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, json jData, string sTable = AI_TABLE); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +json ai_GetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE); +// Saves Associate AIModes and MagicModes to the database. +void aiSaveAssociateModesToDb(object oPlayer, object oAssociate); +// Checks Associate local data and if none is found will initialize or load the +// correct data for oAssociate. +void ai_CheckAssociateData(object oPlayer, object oAssociate, string sAssociateType, int bLoad = FALSE); +// Checks DM's local data and if none is found will initizlize or load the +// correct data for oPlayer. +void ai_CheckDMData(object oPlayer); +// Adds to jPlugins functions after checking if the plugin can be installed. +json ai_Plugin_Add(object oPC, json jPlugins, string sPluginScript); +// Updates the players Plugin list and saves to the database. +json ai_UpdatePluginsForPC(object oPC); +// Updates the DM's Plugin list and saves to the database. +json ai_UpdatePluginsForDM (object oPC); +// Runs all plugins that are loaded into the database. +void ai_StartupPlugins(object oPC); +void ai_SetAIRules() +{ + object oModule = GetModule(); + ai_CheckCampaignDataAndInitialize(); + json jRules = ai_GetCampaignDbJson("rules"); + if(JsonGetType(JsonObjectGet(jRules, AI_RULE_MORAL_CHECKS)) == JSON_TYPE_NULL) + { + jRules = JsonObject(); + // Variable name set to a creatures full name to set debugging on. + jRules = JsonObjectSet(jRules, AI_RULE_DEBUG_CREATURE, JsonString("")); + // Moral checks on or off. + SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, AI_MORAL_CHECKS); + jRules = JsonObjectSet(jRules, AI_RULE_MORAL_CHECKS, JsonInt(AI_MORAL_CHECKS)); + // Allows monsters to prebuff before combat starts. + SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, AI_PREBUFF); + jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(AI_PREBUFF)); + // Allows monsters cast summons spells when prebuffing. + SetLocalInt(oModule, AI_RULE_PRESUMMON, AI_PRESUMMONS); + jRules = JsonObjectSet(jRules, AI_RULE_PRESUMMON, JsonInt(AI_PRESUMMONS)); + // Allows monsters to use tactical AI scripts. + SetLocalInt(oModule, AI_RULE_AMBUSH, AI_TACTICAL); + jRules = JsonObjectSet(jRules, AI_RULE_AMBUSH, JsonInt(AI_TACTICAL)); + // Enemies may summon familiars and Animal companions and will be randomized. + SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, AI_SUMMON_COMPANIONS); + jRules = JsonObjectSet(jRules, AI_RULE_SUMMON_COMPANIONS, JsonInt(AI_SUMMON_COMPANIONS)); + // Allow the AI to move during combat base on the situation and action taking. + SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, AI_ADVANCED_MOVEMENT); + jRules = JsonObjectSet(jRules, AI_RULE_ADVANCED_MOVEMENT, JsonInt(AI_ADVANCED_MOVEMENT)); + // Follow Item Level Restrictions for monsters/associates. + SetLocalInt(oModule, AI_RULE_ILR, AI_ITEM_LEVEL_RESTRICTIONS); + jRules = JsonObjectSet(jRules, AI_RULE_ILR, JsonInt(AI_ITEM_LEVEL_RESTRICTIONS)); + // Allow the AI to use Use Magic Device. + SetLocalInt(oModule, AI_RULE_ALLOW_UMD, AI_USE_MAGIC_DEVICE); + jRules = JsonObjectSet(jRules, AI_RULE_ALLOW_UMD, JsonInt(AI_USE_MAGIC_DEVICE)); + // Allow the AI to use healing kits. + SetLocalInt(oModule, AI_RULE_HEALERSKITS, AI_HEALING_KITS); + jRules = JsonObjectSet(jRules, AI_RULE_HEALERSKITS, JsonInt(AI_HEALING_KITS)); + // Associates are permanent and don't get removed when the master dies. + SetLocalInt(oModule, AI_RULE_PERM_ASSOC, AI_COMPANIONS_PERMANENT); + jRules = JsonObjectSet(jRules, AI_RULE_PERM_ASSOC, JsonInt(AI_COMPANIONS_PERMANENT)); + // Monster AI's chance to attack the weakest target instead of the nearest. + SetLocalInt(oModule, AI_RULE_AI_DIFFICULTY, AI_TARGET_WEAKEST); + jRules = JsonObjectSet(jRules, AI_RULE_AI_DIFFICULTY, JsonInt(AI_TARGET_WEAKEST)); + // Monster AI's distance they can search for the enemy. + SetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE, AI_SEARCH_DISTANCE); + jRules = JsonObjectSet(jRules, AI_RULE_PERCEPTION_DISTANCE, JsonFloat(AI_SEARCH_DISTANCE)); + // Enemy corpses remain on the floor instead of dissappearing. + SetLocalInt(oModule, AI_RULE_CORPSES_STAY, AI_CORPSE_REMAIN); + jRules = JsonObjectSet(jRules, AI_RULE_CORPSES_STAY, JsonInt(AI_CORPSE_REMAIN)); + // Monsters will wander around when not in combat. + SetLocalInt(oModule, AI_RULE_WANDER, AI_WANDER); + jRules = JsonObjectSet(jRules, AI_RULE_WANDER, JsonInt(AI_WANDER)); + // Increase the number of encounter creatures. + SetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS, 0.0); + jRules = JsonObjectSet(jRules, AI_INCREASE_ENC_MONSTERS, JsonFloat(0.0)); + // Increase all monsters hitpoints by this percentage. + SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, 0); + jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(0)); + // Monster's perception distance. + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, AI_MONSTER_PERCEPTION); + jRules = JsonObjectSet(jRules, AI_RULE_MON_PERC_DISTANCE, JsonInt(AI_MONSTER_PERCEPTION)); + // Variable name set to hold the maximum number of henchman the player wants. + int nMaxHenchmen = GetMaxHenchmen(); + SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, nMaxHenchmen); + jRules = JsonObjectSet(jRules, AI_RULE_MAX_HENCHMAN, JsonInt(nMaxHenchmen)); + // Monster AI's distance they can wander away from their spawn point. + SetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE, AI_WANDER_DISTANCE); + jRules = JsonObjectSet(jRules, AI_RULE_WANDER_DISTANCE, JsonFloat(AI_WANDER_DISTANCE)); + // Monsters will open doors when wandering around and not in combat. + SetLocalInt(oModule, AI_RULE_OPEN_DOORS, AI_WANDER); + jRules = JsonObjectSet(jRules, AI_RULE_OPEN_DOORS, JsonInt(AI_OPEN_DOORS)); + // If the modules default XP has not been set then we do it here. + int nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE); + if(nDefaultXP == 0) + { + int nValue = GetModuleXPScale(); + if(nValue != 0) SetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE, nValue); + } + // Variable name set to allow the game to regulate experience based on party size. + SetLocalInt(oModule, AI_RULE_PARTY_SCALE, AI_PARTY_SCALE); + jRules = JsonObjectSet(jRules, AI_RULE_PARTY_SCALE, JsonInt(AI_PARTY_SCALE)); + SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, JsonArray()); + jRules = JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, JsonArray()); + // Variable name set to allow access to widget buttons for the players. + SetLocalInt(oModule, sDMWidgetAccessVarname, AI_DM_WIDGET_ACCESS_BUTTONS); + jRules = JsonObjectSet(jRules, sDMWidgetAccessVarname, JsonInt(AI_DM_WIDGET_ACCESS_BUTTONS)); + // Variable name set to allow access to widget buttons for the players. + SetLocalInt(oModule, sDMAIAccessVarname, AI_DM_AI_ACCESS_BUTTONS); + jRules = JsonObjectSet(jRules, sDMAIAccessVarname, JsonInt(AI_DM_AI_ACCESS_BUTTONS)); + ai_SetCampaignDbJson("rules", jRules); + } + else + { + // Variable name set to a creatures full name to set debugging on. + string sValue = JsonGetString(JsonObjectGet(jRules, AI_RULE_DEBUG_CREATURE)); + SetLocalString(oModule, AI_RULE_DEBUG_CREATURE, sValue); + // Moral checks on or off. + int bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MORAL_CHECKS)); + SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, bValue); + // Allows monsters to prebuff before combat starts. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_BUFF_MONSTERS)); + SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bValue); + // Allows monsters cast summons spells when prebuffing. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PRESUMMON)); + SetLocalInt(oModule, AI_RULE_PRESUMMON, bValue); + // Allows monsters to use ambush AI scripts. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_AMBUSH)); + SetLocalInt(oModule, AI_RULE_AMBUSH, bValue); + // Enemies may summon familiars and Animal companions and will be randomized. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_SUMMON_COMPANIONS)); + SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, bValue); + // Allow the AI to move during combat base on the situation and action taking. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ADVANCED_MOVEMENT)); + SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, bValue); + // Follow Item Level Restrictions for monsters/associates. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ILR)); + SetLocalInt(oModule, AI_RULE_ILR, bValue); + // Allow the AI to use Use Magic Device. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ALLOW_UMD)); + SetLocalInt(oModule, AI_RULE_ALLOW_UMD, bValue); + // Allow the AI to use healing kits. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_HEALERSKITS)); + SetLocalInt(oModule, AI_RULE_HEALERSKITS, bValue); + // Associates are permanent and don't get removed when the owner dies. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PERM_ASSOC)); + SetLocalInt(oModule, AI_RULE_PERM_ASSOC, bValue); + // Monster AI's chance to attack the weakest target instead of the nearest. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_AI_DIFFICULTY)); + SetLocalInt(oModule, AI_RULE_AI_DIFFICULTY, bValue); + // Monster AI's perception distance from player. + float fValue = JsonGetFloat(JsonObjectGet(jRules, AI_RULE_PERCEPTION_DISTANCE)); + SetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE, fValue); + // Enemy corpses remain on the floor instead of dissappearing. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_CORPSES_STAY)); + SetLocalInt(oModule, AI_RULE_CORPSES_STAY, bValue); + // Monsters will wander around when not in combat. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_WANDER)); + SetLocalInt(oModule, AI_RULE_WANDER, bValue); + // Increase the number of encounter creatures. + fValue = JsonGetFloat(JsonObjectGet(jRules, AI_INCREASE_ENC_MONSTERS)); + SetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS, fValue); + // Increase all monsters hitpoints by this percentage. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_INCREASE_MONSTERS_HP)); + SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, bValue); + // Monster's perception distance. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MON_PERC_DISTANCE)); + if(bValue < 8 || bValue > 11) bValue = 11; + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, bValue); + // Variable name set to hold the maximum number of henchman the player wants. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MAX_HENCHMAN)); + if(bValue == 0) bValue = GetMaxHenchmen(); + else SetMaxHenchmen(bValue); + SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, bValue); + // Monster AI's wander distance from their spawn point. + fValue = JsonGetFloat(JsonObjectGet(jRules, AI_RULE_WANDER_DISTANCE)); + SetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE, fValue); + // Monsters will open doors while wandering around and not in combat. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_OPEN_DOORS)); + SetLocalInt(oModule, AI_RULE_OPEN_DOORS, bValue); + // If the modules default XP has not been set then we do it here. + int nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE); + if(nDefaultXP == 0) + { + bValue = GetModuleXPScale(); + if(bValue != 0) SetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE, bValue); + } + // Variable name set to allow the game to regulate experience based on party size. + bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PARTY_SCALE)); + if(bValue) + { + int nBasePartyXP = GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP); + if(nBasePartyXP == 0) + { + nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE); + SetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP, nDefaultXP); + } + } + SetLocalInt(oModule, AI_RULE_PARTY_SCALE, bValue); + json jRSpells = JsonObjectGet(jRules, AI_RULE_RESTRICTED_SPELLS); + if(JsonGetType(jRSpells) == JSON_TYPE_NULL) + { + jRSpells = JsonArray(); + jRules = JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, jRSpells); + ai_SetCampaignDbJson("rules", jRules); + } + SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, jRSpells); + // Variable name set to allow access to widget buttons for the players. + bValue = JsonGetInt(JsonObjectGet(jRules, sDMWidgetAccessVarname)); + SetLocalInt(oModule, sDMWidgetAccessVarname, bValue); + // Variable name set to allow access to widget buttons for the players. + bValue = JsonGetInt(JsonObjectGet(jRules, sDMAIAccessVarname)); + SetLocalInt(oModule, sDMAIAccessVarname, bValue); + } +} +int ai_GetIsCharacter(object oCreature) +{ + return (GetIsPC(oCreature) && !GetIsDM(oCreature) && !GetIsDMPossessed(oCreature)); +} +int ai_GetIsDungeonMaster(object oCreature) +{ + return (GetIsDM(oCreature) || GetIsDMPossessed(oCreature)); +} +object ai_GetPlayerMaster(object oAssociate) +{ + if(ai_GetIsCharacter(oAssociate)) return oAssociate; + object oMaster = GetMaster(oAssociate); + if(ai_GetIsCharacter(oMaster)) return oMaster; + return OBJECT_INVALID; +} +int ai_GetPercHPLoss(object oCreature) +{ + int nHP = GetCurrentHitPoints(oCreature); + if(nHP < 1) return 0; + return(nHP * 100) / GetMaxHitPoints(oCreature); +} +int ai_RollDiceString(string sDice) +{ + int nNegativePos, nBonus = 0; + string sRight = GetStringRight(sDice, GetStringLength(sDice) - FindSubString(sDice, "d") - 1); + int nPlusPos = FindSubString(sRight, "+"); + if(nPlusPos != -1) + { + nBonus = StringToInt(GetStringRight(sRight, GetStringLength(sRight) - nPlusPos - 1)); + sRight = GetStringLeft(sRight, nPlusPos); + } + else + { + nNegativePos = FindSubString(sRight, "-"); + if(nNegativePos != -1) + { + nBonus = StringToInt(GetStringRight(sRight, GetStringLength(sRight) - nNegativePos - 1)); + sRight = GetStringLeft(sRight, nNegativePos); + nBonus = nBonus * -1; + } + } + int nDie = StringToInt(sRight); + int nNumOfDie = StringToInt(GetStringLeft(sDice, FindSubString(sDice, "d"))); + int nResult; + while(nNumOfDie > 0) + { + nResult += Random(nDie) + 1; + nNumOfDie --; + } + return nResult + nBonus; +} +int ai_HexStringToInt(string sString) +{ + sString = GetStringLowerCase(sString); + int nInt = 0; + int nLength = GetStringLength(sString); + int i; + for(i = nLength - 1; i >= 0; i--) + { + int n = FindSubString("0123456789abcdef", GetSubString(sString, i, 1)); + if(n == -1) return nInt; + nInt |= n << ((nLength - i - 1) * 4); + } + return nInt; +} +float ai_GetCosAngleBetween(object oObject1, object oObject2) +{ + vector v1 = GetPositionFromLocation(GetLocation(oObject1)); + vector v2 = GetPositionFromLocation(GetLocation(oObject2)); + vector v3 = GetPositionFromLocation(GetLocation(OBJECT_SELF)); + + v1.x -= v3.x; v1.y -= v3.y; v1.z -= v3.z; + v2.x -= v3.x; v2.y -= v3.y; v2.z -= v3.z; + + float dotproduct = v1.x*v2.x+v1.y*v2.y+v1.z*v2.z; + + return dotproduct/(VectorMagnitude(v1)*VectorMagnitude(v2)); +} +string ai_RemoveIllegalCharacters(string sString, string sLegal = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") +{ + string sOut, sValue; + sString = ai_StripColorCodes(sString); + int nLength = GetStringLength(sString); + int Cnt; + for(Cnt = 0; Cnt != nLength; ++Cnt) + { + sValue = GetSubString(sString, Cnt, 1); + if(TestStringAgainstPattern("**" + sValue + "**", sLegal)) + sOut += sValue; + } + return sOut; +} +int ai_GetCharacterLevels(object oCreature) +{ + int nLevels, nPosition = 1; + while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + nLevels += GetLevelByPosition(nPosition, oCreature); + nPosition++; + } + return nLevels; +} +string ai_StringReplaceText(string sSource, string sFind, string sReplace) +{ + int nFindLength = GetStringLength(sFind); + int nPosition = 0; + string sReturnValue = ""; + // Locate all occurences of sFind. + int nFound = FindSubString(sSource, sFind); + while(nFound >= 0 ) + { + // Build the return string, replacing this occurence of sFind with sReplace. + sReturnValue += GetSubString(sSource, nPosition, nFound - nPosition) + sReplace; + nPosition = nFound + nFindLength; + nFound = FindSubString(sSource, sFind, nPosition); + } + // Tack on the end of sSource and return. + return sReturnValue + GetStringRight(sSource, GetStringLength(sSource) - nPosition); +} +string ai_GetStringArray(string sArray, int nIndex, string sSeperator = ":") +{ + int nCnt = 0, nMark = 0, nStringLength = GetStringLength(sArray); + string sCharacter; + // Search the string. + while(nCnt < nStringLength) + { + sCharacter = GetSubString(sArray, nCnt, 1); + // Look for the mark. + if(sCharacter == sSeperator) + { + // If we have not found it then lets see if this mark is the one. + if(nMark < 1) + { + // If we are down to 0 in the index then we have found the mark. + if(nIndex > 0) nIndex --; + // Mark the start of the string we need. + else nMark = nCnt + 1; + } + else + { + // We have the first mark so the next mark will mean we have the string we need. + // Now pull it and return. + sArray = GetSubString(sArray, nMark, nCnt - nMark); + return sArray; + } + } + nCnt ++; + } + // If we hit the end without finding it then return "" as an error. + return ""; +} +string ai_SetStringArray(string sArray, int nIndex, string sField, string sSeperator = ":") +{ + int nCnt = 1, nMark = 1, nStringLength = GetStringLength(sArray); + int nIndexCounter = 0; + string sCharacter, sNewArray = sSeperator, sText; + // Check to make sure this is not a new array. + // If it is new then set it with 1 slot. + if(nStringLength < 2) + { + sArray = sSeperator + " " + sSeperator; + nStringLength = 3; + } + // Search the string. + while(nCnt <= nStringLength) + { + sCharacter = GetSubString(sArray, nCnt, 1); + // Look for the mark. + if(sCharacter == sSeperator) + { + // First check to see if this is the index we are replacing. + if(nIndex == nIndexCounter) sText = sField; + else + { + // Get the original text for this field. + sText = GetSubString(sArray, nMark, nCnt - nMark); + } + // Add the field to the new index. + sNewArray = sNewArray + sText + sSeperator; + // Now set the marker to the new starting point. + nMark = nCnt + 1; + // Increase the index counter as well. + nIndexCounter ++; + } + nCnt ++; + } + // if we are at the end of the array and still have not set the data + // then add blank data until we get to the correct index. + while(nIndexCounter <= nIndex) + { + // If they match add the field. + if(nIndexCounter == nIndex) sNewArray = sNewArray + sField + sSeperator; + // Otherwise just add a blank field. + else sNewArray = sNewArray + " " + sSeperator; + nIndexCounter ++; + } + // When done return the new array. + return sNewArray; +} +int ai_GetNumberOfProperties(object oItem) +{ + int nNumOfProperties = 0, nPropertyType, nPropertySubType; + // Get first property + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + // Ignore double type properties such as bane. + nPropertyType = GetItemPropertyType(ipProperty); + switch(nPropertyType) + { + // Skip these properties as they don't count. + case 8 : break; // EnhanceAlignmentGroup + case 44 : break; // Light + case 62 : break; // UseLimitationAlignmentGroup + case 63 : break; // UseLimitationClass + case 64 : break; // UseLimitationRacial + case 65 : break; // UseLimitationSpecificAlignment + case 66 : break; // UseLimitationTerrain + case 86 : break; // Quality + case 150 : break; // UseLimitationGender + case 15 : + { + nPropertySubType = GetItemPropertySubType(ipProperty); + if(nPropertySubType == IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY) break; + if(nPropertySubType == IP_CONST_CASTSPELL_UNIQUE_POWER) break; + } + default : nNumOfProperties ++; + } + // Get the next property + ipProperty = GetNextItemProperty(oItem); + } + // Reduce the number of properties by one on whips. + if(GetBaseItemType(oItem) == BASE_ITEM_WHIP) nNumOfProperties --; + return nNumOfProperties; +} +void ai_CreateCampaignDataTable() +{ + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, + "CREATE TABLE IF NOT EXISTS " + AI_TABLE + "(" + + "name TEXT, " + + "plugins TEXT, " + + "rules TEXT, " + + "PRIMARY KEY(name));"); + SqlStep(sql); + //if(AI_DEBUG) ai_Debug("0i_main", "343", We are creating a campaign table [" + + // AI_TABLE + "] in the database."); +} +void ai_CheckCampaignDataTableAndCreateTable() +{ + string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " + + "AND name =@table;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@table", AI_TABLE); + if(!SqlStep(sql)) ai_CreateCampaignDataTable(); +} +void ai_InitializeCampaignData() +{ + string sQuery = "INSERT INTO " + AI_TABLE + "(name, plugins, rules) " + + "VALUES(@name, @plugins, @rules);"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@name", "PEPS_DATA"); + SqlBindJson(sql, "@plugins", JsonArray()); + SqlBindJson(sql, "@rules", JsonObject()); + SqlStep(sql); +} +void ai_CheckCampaignDataAndInitialize() +{ + ai_CheckCampaignDataTableAndCreateTable(); + string sQuery = "SELECT name FROM " + AI_TABLE + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@name", "PEPS_DATA"); + if(!SqlStep(sql)) ai_InitializeCampaignData(); +} +void ai_CreateDMDataTable() +{ + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, + "CREATE TABLE IF NOT EXISTS " + AI_DM_TABLE + "(" + + "name TEXT, " + + "buttons TEXT, " + + "plugins TEXT, " + + "locations TEXT, " + + "options TEXT, " + + "saveslots TEXT, " + + "PRIMARY KEY(name));"); + SqlStep(sql); +} +void ai_CheckDMDataTableAndCreateTable() +{ + string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " + + "AND name =@table;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@table", AI_DM_TABLE); + if(!SqlStep(sql)) ai_CreateDMDataTable(); +} +void ai_InitializeDMData(string sName) +{ + string sQuery = "INSERT INTO " + AI_DM_TABLE + "(name, buttons, plugins, " + + "locations, options, saveslots) " + + "VALUES(@name, @buttons, @plugins, @locations, @options, @saveslots);"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindJson(sql, "@buttons", JsonArray()); + SqlBindJson(sql, "@plugins", JsonArray()); + SqlBindJson(sql, "@locations", JsonObject()); + SqlBindJson(sql, "@options", JsonObject()); + SqlBindJson(sql, "@saveslots", JsonObject()); + SqlStep(sql); +} +void ai_CheckDMDataAndInitialize(object oDM) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oDM))); + string sQuery = "SELECT name FROM " + AI_DM_TABLE + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@name", sName); + if(!SqlStep(sql)) + { + ai_CheckDMDataTableAndCreateTable(); + ai_InitializeDMData(sName); + } +} +void ai_SetCampaignDbJson(string sDataField, json jData, string sName = "PEPS_DATA", string sTable = AI_TABLE) +{ + string sQuery = "UPDATE " + sTable + " SET " + sDataField + + " = @data WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindJson(sql, "@data", jData); + SqlBindString(sql, "@name", sName); + SqlStep(sql); +} +json ai_GetCampaignDbJson(string sDataField, string sName = "PEPS_DATA", string sTable = AI_TABLE) +{ + string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery); + SqlBindString(sql, "@name", sName); + json jReturn; + if(SqlStep(sql)) return SqlGetJson (sql, 0); + else return JsonArray(); + return jReturn; +} +void ai_CreateAssociateDataTable(object oPlayer) +{ + sqlquery sql = SqlPrepareQueryObject(oPlayer, + "CREATE TABLE IF NOT EXISTS " + AI_TABLE + "(" + + "name TEXT, " + + "modes TEXT, " + + "buttons TEXT, " + + "aidata TEXT, " + + "lootfilters TEXT, " + + "plugins TEXT, " + + "locations TEXT, " + + "PRIMARY KEY(name));"); + SqlStep(sql); + //ai_Debug("0i_main", "665", GetName(oPlayer) + " is creating a table [" + + // AI_TABLE + "] in the database."); +} +void ai_CheckDataTableAndCreateTable(object oPlayer) +{ + string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " + + "AND name =@table;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@table", AI_TABLE); + if(!SqlStep(sql)) ai_CreateAssociateDataTable (oPlayer); + //else SendMessageToPC(oPlayer, "0i_main, 675, " + GetName(oPlayer) + " has a database with table [" + AI_TABLE + "]."); +} +void ai_InitializeAssociateData(object oPlayer, string sAssociateType) +{ + string sQuery = "INSERT INTO " + AI_TABLE + "(name, modes, buttons, " + + "aidata, lootfilters, plugins, locations) " + + "VALUES(@name, @modes, @buttons, @aidata, @lootfilters, @plugins, @locations);"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociateType); + SqlBindJson(sql, "@modes", JsonArray()); + SqlBindJson(sql, "@buttons", JsonArray()); + SqlBindJson(sql, "@aidata", JsonArray()); + SqlBindJson(sql, "@lootfilters", JsonArray()); + SqlBindJson(sql, "@plugins", JsonArray()); + SqlBindJson(sql, "@locations", JsonObject()); + //SendMessageToPC(oPlayer, "0i_main, 690, " + GetName(oPlayer) + " is initializing associate " + + // sAssociateType + " data for table [" + AI_TABLE + "]."); + SqlStep(sql); +} +void ai_CheckAssociateDataAndInitialize(object oPlayer, string sAssociateType) +{ + ai_CheckDataTableAndCreateTable(oPlayer); + string sQuery = "SELECT name FROM " + AI_TABLE + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject (oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociateType); + if(!SqlStep(sql)) ai_InitializeAssociateData(oPlayer, sAssociateType); + //else SendMessageToPC(oPlayer, "0i_main, 701, sAssociateType: " + sAssociateType + + // " returns: " + SqlGetString(sql, 0)); +} +string ai_GetAssociateType(object oPlayer, object oAssociate) +{ + if(GetIsPC(oAssociate)) return "pc"; + string sAITag = GetLocalString(oAssociate, AI_TAG); + if(sAITag == "") + { + int nAssociateType = GetAssociateType(oAssociate); + if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) sAITag = "companion"; + else if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) sAITag = "familiar"; + else if(nAssociateType == ASSOCIATE_TYPE_SUMMONED) sAITag = "summons"; + else if(nAssociateType == ASSOCIATE_TYPE_DOMINATED) sAITag = "dominated"; + else if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) sAITag = GetTag(oAssociate); + string sCurrentAITag; + // Check for duplicate tags and change. + int nIndex; + object oCreature; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oCreature = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPlayer, nIndex); + if(oAssociate != oCreature && sAITag == GetTag(oCreature)) sAITag += IntToString(Random(1000)); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oCreature = GetAssociate(nIndex, oPlayer, 1); + if(oAssociate != oCreature && sAITag == GetTag(oCreature)) sAITag += IntToString(Random(1000)); + } + SetLocalString(oAssociate, AI_TAG, sAITag); + } + return sAITag; +} +void ai_SetAssociateDbInt(object oPlayer, string sAssociatetype, string sDataField, int nData, string sTable = AI_TABLE) +{ + string sQuery = "UPDATE " + sTable + " SET " + sDataField + + " = @data WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociatetype); + SqlBindInt(sql, "@data", nData); + //ai_Debug("0i_main", "368", "SETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " + + // sAssociatetype + " sDataField: " + sDataField + " nData: " + IntToString(nData)); + SqlStep(sql); +} +int ai_GetAssociateDbInt(object oPlayer, string sAssociatetype, string sDataField, string sTable = AI_TABLE) +{ + string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociatetype); + //ai_Debug("0i_main", "377", "GETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " + + // sAssociatetype + " sDataField: " + sDataField); + if(SqlStep(sql)) return SqlGetInt(sql, 0); + else return 0; +} +void ai_SetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, float fData, string sTable = AI_TABLE) +{ + string sQuery = "UPDATE " + sTable + " SET " + sDataField + + " = @data WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociatetype); + SqlBindFloat(sql, "@data", fData); + //ai_Debug("0i_main", "368", "SETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " + + // sAssociatetype + " sDataField: " + sDataField + " fData: " + FloatToString(fData, 0, 0)); + SqlStep(sql); +} +float ai_GetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, string sTable = AI_TABLE) +{ + string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sAssociatetype); + //ai_Debug("0i_main", "377", "GETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " + + // sAssociatetype + " sDataField: " + sDataField); + if(SqlStep(sql)) return SqlGetFloat(sql, 0); + else return 0.0; +} +void ai_SetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, json jData, string sTable = AI_TABLE) +{ + //SendMessageToPC(oPlayer, "0i_main, 629, Set DbJson - sAssociateType: " + sAssociateType + " sDataField: " + sDataField + " jData: " + JsonDump(jData)); + string sQuery = "UPDATE " + sTable + " SET " + sDataField + + " = @data WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindJson(sql, "@data", jData); + SqlBindString(sql, "@name", sAssociateType); + SqlStep(sql); +} +json ai_GetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE) +{ + //SendMessageToPC(oPlayer, "0i_main, 638, Get DbJson - sAssociateType: " + sAssociateType + " sDataField: " + sDataField); + string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString (sql, "@name", sAssociateType); + if(SqlStep(sql)) + { + json jReturn = SqlGetJson(sql, 0); + //SendMessageToPC(oPlayer, "0i_main, 646 jReturn: " + JsonDump(jReturn, 1)); + if(JsonGetType(jReturn) == JSON_TYPE_NULL) return JsonArray(); + return jReturn; + } + else return JsonNull(); +} +void aiSaveAssociateModesToDb(object oPlayer, object oAssociate) +{ + string sAssociateType = ai_GetAssociateType(oPlayer, oAssociate); + json jModes = ai_GetAssociateDbJson(oPlayer, sAssociateType, "modes"); + int nAIMode = GetLocalInt(oAssociate, sAIModeVarname); + jModes = JsonArraySet(jModes, 0, JsonInt(nAIMode)); + int nMagicMode = GetLocalInt(oAssociate, sMagicModeVarname); + jModes = JsonArraySet(jModes, 1, JsonInt(nMagicMode)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes); +} +void ai_SetupModes(object oPlayer, object oAssociate, string sAssociateType) +{ + json jModes = JsonArray(); + jModes = JsonArrayInsert(jModes, JsonInt(0)); // AI Modes. + // Set magic modes to use Normal magic, Bit 256. + jModes = JsonArrayInsert(jModes, JsonInt(256)); // Magic Modes. + SetLocalInt(oAssociate, sMagicModeVarname, 256); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes, AI_TABLE); +} +void ai_SetupButtons(object oPlayer, object oAssociate, string sAssociateType) +{ + json jButtons = JsonArray(); + jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // Command buttons. + jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // AI buttons. + jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // AI buttons 2. + ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons, AI_TABLE); +} +void ai_SetupAIData(object oPlayer, object oAssociate, string sAssociateType) +{ + json jAIData = JsonArray(); + jAIData = JsonArrayInsert(jAIData, JsonInt(0)); // 0 - Difficulty adjustment. + jAIData = JsonArrayInsert(jAIData, JsonInt(70)); // 1 - Heal out of combat. + SetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT, 70); + jAIData = JsonArrayInsert(jAIData, JsonInt(50)); // 2 - Heal in combat. + SetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT, 50); + jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 3 - Loot check range. + SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, 20.0); + jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 4 - Lock check range. + SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, 20.0); + jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 5 - Trap check range. + SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, 20.0); + jAIData = JsonArrayInsert(jAIData, JsonFloat(3.0)); // 6 - Associate Distance. + SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, 3.0); + // This can be replaced as it is not used in the database. + // We keep it for now as we don't want to move other data. + jAIData = JsonArrayInsert(jAIData, JsonInt(11)); // 7 - Associate Perception DistanceDistance. + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, 11); + SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, 20.0); + jAIData = JsonArrayInsert(jAIData, JsonString("")); // 8 - Associate Combat Tactics. + jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 9 - Open Doors check range. + SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, 20.0); + json jSpells = JsonArray(); + jAIData = JsonArrayInsert(jAIData, jSpells); // 10 - Castable spells. + ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData, AI_TABLE); +} +void ai_SetupLootFilters(object oPlayer, object oAssociate, string sAssociateType) +{ + json jLootFilters = JsonArray(); + // Maximum weight to pickup an item. + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(200)); + SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, 200); + // Bitwise int for checkbox pickup filter. + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(AI_LOOT_ALL_ON)); + SetLocalInt(oAssociate, sLootFilterVarname, AI_LOOT_ALL_ON); + // Minimum gold value to pickup. + int nIndex; + for(nIndex = 2; nIndex < 20; nIndex++) + { + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(0)); + } + ai_SetAssociateDbJson(oPlayer, sAssociateType, "lootfilters", jLootFilters, AI_TABLE); +} +void ai_SetupLocations(object oPlayer, object oAssociate, string sAssociateType) +{ + json jLocations = JsonObject(); + json jNUI = JsonObject(); + jNUI = JsonObjectSet(jNUI, "x", JsonFloat(-1.0)); + jNUI = JsonObjectSet(jNUI, "y", JsonFloat(-1.0)); + if(ai_GetIsCharacter(oAssociate)) + { + jLocations = JsonObjectSet(jLocations, AI_MAIN_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, AI_PLUGIN_NUI, jNUI); + } + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_COMMAND_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_LOOTFILTER_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_COPY_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_QUICK_WIDGET_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_SPELL_MEMORIZE_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_SPELL_KNOWN_NUI, jNUI); + jNUI = JsonObjectSet(jNUI, "x", JsonFloat(0.0)); + jNUI = JsonObjectSet(jNUI, "y", JsonFloat(0.0)); + jLocations = JsonObjectSet(jLocations, sAssociateType + AI_WIDGET_NUI, jNUI); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "locations", jLocations, AI_TABLE); +} +void ai_SetupAssociateData(object oPlayer, object oAssociate, string sAssociateType) +{ + //ai_Debug("0i_main", "744", GetName(oAssociate) + " is initializing associate data."); + ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType); + // Default behavior for associates at start. + ai_SetupModes(oPlayer, oAssociate, sAssociateType); + ai_SetupButtons(oPlayer, oAssociate, sAssociateType); + ai_SetupAIData(oPlayer, oAssociate, sAssociateType); + ai_SetupLootFilters(oPlayer, oAssociate, sAssociateType); + // ********** Plugins ************ + // These are pulled straight from the database. + ai_SetupLocations(oPlayer, oAssociate, sAssociateType); +} +void ai_RestoreDatabase(object oPlayer, object oAssociate, string sAssociateType) +{ + // ********** Modes ********** + json jModes = JsonArray(); + // AI Modes (0). + int nValue = GetLocalInt(oAssociate, sAIModeVarname); + jModes = JsonArrayInsert(jModes, JsonInt(nValue)); + // Magic Modes (1). + nValue = GetLocalInt(oAssociate, sMagicModeVarname); + jModes = JsonArrayInsert(jModes, JsonInt(nValue)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes, AI_TABLE); + // ********** Buttons ********** + json jButtons = JsonArray(); + // Command buttons (0). + nValue = GetLocalInt(oAssociate, sWidgetButtonsVarname); + jButtons = JsonArrayInsert(jButtons, JsonInt(nValue)); + // AI buttons Group 1 (1). + nValue = GetLocalInt(oAssociate, sAIButtonsVarname); + jButtons = JsonArrayInsert(jButtons, JsonInt(nValue)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons, AI_TABLE); + // ********** AI Data ********** + json jAIData = JsonArray(); + nValue = GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT); + jAIData = JsonArrayInsert(jAIData, JsonInt(nValue)); + nValue = GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT); + jAIData = JsonArrayInsert(jAIData, JsonInt(nValue)); + nValue = GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT); + jAIData = JsonArrayInsert(jAIData, JsonInt(nValue)); + float fValue = GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE); + jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue)); + fValue = GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE); + jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue)); + fValue = GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE); + jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue)); + fValue = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE); + jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue)); + nValue = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION); + jAIData = JsonArrayInsert(jAIData, JsonInt(nValue)); + float fRange = 20.0; + if(nValue == 8) fRange = 10.0; + else if(nValue == 10) fRange = 35.0; + SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, fRange); + string sValue = GetLocalString(oAssociate, AI_DEFAULT_SCRIPT); + jAIData = JsonArrayInsert(jAIData, JsonString(sValue)); + fValue = GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE); + jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue)); + json jValue = GetLocalJson(oPlayer, AI_SPELLS_WIDGET); + if(JsonGetType(jValue) == JSON_TYPE_NULL) + { + jValue = JsonArray(); + jValue = JsonArrayInsert(jValue, JsonInt(1)); // 0 - Class selected. + jValue = JsonArrayInsert(jValue, JsonInt(10)); // 1 - Level selected. + jValue = JsonArrayInsert(jValue, JsonArray()); // Spell list for widget. + SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jValue); + } + jAIData = JsonArrayInsert(jAIData, jValue); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData); + // ********** LootFilters ********** + json jLootFilters = JsonArray(); + nValue = GetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT); + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue)); + nValue = GetLocalInt(oAssociate, sLootFilterVarname); + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue)); + int nIndex; + for(nIndex = 2; nIndex < 20; nIndex++) + { + nValue = GetLocalInt(oAssociate, AI_MIN_GOLD_ + IntToString(nIndex)); + jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue)); + } + ai_SetAssociateDbJson(oPlayer, sAssociateType, "lootfilters", jLootFilters, AI_TABLE); + // ********** Plugins ************ + // These are pulled straight from the database. + // ********** Locations ********** + // These are only in the database. +} +void ai_CheckAssociateData(object oPlayer, object oAssociate, string sAssociateType, int bLoad = FALSE) +{ + //ai_Debug("0i_main", "810", "Checking data for oAssociate: " + GetName(oAssociate)); + // Do quick check to see if they have a variable saved if so then exit. + if(GetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE) != 0.0) + { + if(!bLoad) return; + // If the database gets destroyed lets drop an error and restore values + // from the locals. + ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType); + ai_RestoreDatabase(oPlayer, oAssociate, sAssociateType); + return; + } + ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType); + // ********** Modes ********** + json jModes = ai_GetAssociateDbJson(oPlayer, sAssociateType, "modes"); + if(JsonGetType(JsonArrayGet(jModes, 0)) == JSON_TYPE_NULL) + { + ai_SetupModes(oPlayer, oAssociate, sAssociateType); + } + else + { + SetLocalInt(oAssociate, sAIModeVarname, JsonGetInt(JsonArrayGet(jModes, 0))); + SetLocalInt(oAssociate, sMagicModeVarname, JsonGetInt(JsonArrayGet(jModes, 1))); + } + // ********** Buttons ********** + json jButtons = ai_GetAssociateDbJson(oPlayer, sAssociateType, "buttons"); + if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL) + { + ai_SetupButtons(oPlayer, oAssociate, sAssociateType); + } + else + { + // ********** Associate Command Buttons ********** + int nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0)); + if(nWidgetButtons) SetLocalInt(oAssociate, sWidgetButtonsVarname, nWidgetButtons); + // ********** Associate AI Buttons ********** + int nAIButtons = JsonGetInt(JsonArrayGet(jButtons, 1)); + if(nAIButtons) SetLocalInt(oAssociate, sAIButtonsVarname, nAIButtons); + } + // ********** AI Data ********** + json jAIData = ai_GetAssociateDbJson(oPlayer, sAssociateType, "aidata"); + if(JsonGetType(JsonArrayGet(jAIData, 0)) == JSON_TYPE_NULL) + { + ai_SetupAIData(oPlayer, oAssociate, sAssociateType); + } + else + { + SetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT, JsonGetInt(JsonArrayGet(jAIData, 0))); + SetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT, JsonGetInt(JsonArrayGet(jAIData, 1))); + SetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT, JsonGetInt(JsonArrayGet(jAIData, 2))); + SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 3))); + SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 4))); + SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 5))); + SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 6))); + int nPercRange = JsonGetInt(JsonArrayGet(jAIData, 7)); + if(nPercRange < 8 || nPercRange > 11) nPercRange = 11; + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, nPercRange); + float fRange = 20.0; + if(nPercRange == 8) fRange = 10.0; + else if(nPercRange == 10) fRange = 35.0; + SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, fRange); + string sScript = JsonGetString(JsonArrayGet(jAIData, 8)); + if(sScript != "") SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript); + json jDoorRange = JsonArrayGet(jAIData, 9); + if(JsonGetType(jDoorRange) == JSON_TYPE_NULL) + { + jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData); + SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, 20.0); + } + else SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, JsonGetFloat(jDoorRange)); + json jSpellsWidget = JsonArrayGet(jAIData, 10); + if(JsonGetType(jSpellsWidget) == JSON_TYPE_NULL) + { + jSpellsWidget = JsonArray(); + jSpellsWidget = JsonArrayInsert(jSpellsWidget, JsonInt(0)); // 0 - Class selected. + jSpellsWidget = JsonArrayInsert(jSpellsWidget, JsonInt(0)); // 1 - Level selected. + jAIData = JsonArrayInsert(jAIData, jSpellsWidget); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData); + SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jSpellsWidget); + } + } + // ********** LootFilters ********** + json jLootFilters = ai_GetAssociateDbJson(oPlayer, sAssociateType, "lootfilters"); + if(JsonGetType(JsonArrayGet(jLootFilters, 0)) == JSON_TYPE_NULL) + { + ai_SetupLootFilters(oPlayer, oAssociate, sAssociateType); + } + else + { + SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, JsonGetInt(JsonArrayGet(jLootFilters, 0))); + SetLocalInt(oAssociate, sLootFilterVarname, JsonGetInt(JsonArrayGet(jLootFilters, 1))); + int nIndex; + for(nIndex = 2; nIndex < 20; nIndex++) + { + SetLocalInt(oAssociate, AI_MIN_GOLD_ + IntToString(nIndex), JsonGetInt(JsonArrayGet(jLootFilters, nIndex))); + } + } + // ********** Plugins ************ + // These are pulled straight from the database. + // ********** Locations ********** + json jLocations = ai_GetAssociateDbJson(oPlayer, sAssociateType, "locations"); + if(JsonGetType(JsonObjectGet(jLocations, AI_WIDGET_NUI)) == JSON_TYPE_NULL) + { + ai_SetupLocations(oPlayer, oAssociate, sAssociateType); + } + // They are always pulled from the database, so no copies to local variables. +} +void ai_SetupDMData(object oPlayer, string sName) +{ + //ai_Debug("0i_main", "870", GetName(oPlayer) + " is initializing DM data."); + ai_CheckDMDataAndInitialize(oPlayer); + // ********** Buttons ********** + json jButtons = JsonArray(); + jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // DM Widget Buttons. + ai_SetCampaignDbJson("buttons", jButtons, sName, AI_DM_TABLE); + // ********** Plugins ************ + // These are pulled straight from the database. + json jPlugins = JsonArray(); + ai_SetCampaignDbJson("plugins", jPlugins, sName, AI_DM_TABLE); + // ********** Locations ********** + json jLocations = JsonObject(); + json jNUI = JsonObject(); + jNUI = JsonObjectSet(jNUI, "x", JsonFloat(-1.0)); + jNUI = JsonObjectSet(jNUI, "y", JsonFloat(-1.0)); + jLocations = JsonObjectSet(jLocations, AI_MAIN_NUI, jNUI); + jLocations = JsonObjectSet(jLocations, AI_PLUGIN_NUI, jNUI); + jNUI = JsonObjectSet(jLocations, "x", JsonFloat(1.0)); + jNUI = JsonObjectSet(jLocations, "y", JsonFloat(1.0)); + jLocations = JsonObjectSet(jLocations, AI_WIDGET_NUI, jNUI); + ai_SetCampaignDbJson("locations", jLocations, sName, AI_DM_TABLE); + // ********** Options ********** + json jOptions = JsonArray(); + ai_SetCampaignDbJson("options", jOptions, sName, AI_DM_TABLE); + // ********** SaveSlots ********** + json jSaveSlots = JsonObject(); + ai_SetCampaignDbJson("saveslots", jSaveSlots, sName, AI_DM_TABLE); +} +void ai_CheckDMData(object oPlayer) +{ + //ai_Debug("0i_main", "898", "Checking data for DM: " + GetName(oPlayer)); + string sName = ai_RemoveIllegalCharacters(GetName(oPlayer)); + // ********** Buttons ********** + json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE); + // if there is no saved AImodes then set the defaults. + if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL) + { + ai_SetupDMData(oPlayer, sName); + } + else + { + //ai_Debug("0i_main", "909", GetName(oPlayer) + " is loading DM data from the database."); + // Get data from the database and place on to the associates and player. + // ********** Buttons ********** + json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE); + if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL) + { + ai_SetupDMData(oPlayer, sName); + } + SetLocalInt(oPlayer, sDMWidgetButtonVarname, JsonGetInt(JsonArrayGet(jButtons, 0))); + // ********** Associate Command Buttons ********** + int nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0)); + SetLocalInt(oPlayer, sDMWidgetButtonVarname, nWidgetButtons); + // ********** Plugins ************ + // These are pulled straight from the database. + // ********** Locations ********** + // These are pulled straight from the database. + // ********** Options ********** + // ********** SaveSltos ********** + } +} +json ai_Plugin_Add(object oPC, json jPlugins, string sPluginScript) +{ + if(ResManGetAliasFor(sPluginScript, RESTYPE_NCS) == "") + { + ai_SendMessages("The script (" + sPluginScript + ") was not found by ResMan!", AI_COLOR_RED, oPC); + return jPlugins; + } + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + if(JsonGetString(JsonArrayGet(jPlugin, 0)) == sPluginScript) + { + ai_SendMessages("Plugin (" + sPluginScript + ") is already installed!", AI_COLOR_RED, oPC); + return jPlugins; + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + SetLocalInt(oPC, AI_ADD_PLUGIN, TRUE); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugins); + ExecuteScript(sPluginScript, oPC); + int nPluginSet = GetLocalInt(oPC, AI_PLUGIN_SET); + // Setting AI_PLUGIN_SET to -1 means the plugin failed to load. + if(nPluginSet == -1) return jPlugins; + if(nPluginSet) + { + jPlugin = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + } + else + { + jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString(sPluginScript)); + jPlugin = JsonArrayInsert(jPlugin, JsonBool(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString(sPluginScript)); + int nCount = JsonGetLength(jPlugins) + 1; + string sIcon = "is_summon" + IntToString(nCount); + jPlugin = JsonArrayInsert(jPlugin, JsonString(sIcon)); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + } + DeleteLocalInt(oPC, AI_ADD_PLUGIN); + DeleteLocalInt(oPC, AI_PLUGIN_SET); + DeleteLocalJson(oPC, AI_JSON_PLUGINS); + return jPlugins; +} +// Temporary function to addapt old plugin json to new plugin json. +json ai_CheckOldPluginJson(object oPC) +{ + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + // If the first array is not an array then this is the old version. + if(JsonGetType(jPlugin) != JSON_TYPE_ARRAY) + { + string sScript; + json jNewPlugins = JsonArray(); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sScript = JsonGetString(jPlugin); + if(sScript != "") jNewPlugins = ai_Plugin_Add(oPC, jNewPlugins, sScript); + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + + } + ai_SetAssociateDbJson(oPC, "pc", "plugins", jNewPlugins); + return jNewPlugins; + } + return jPlugins; +} +json ai_UpdatePluginsForPC(object oPC) +{ + // Check if the server is running or single player. + if(!AI_SERVER) return ai_CheckOldPluginJson(oPC); + int nJsonType, nCounter, nIndex, bWidget, bAllow; + string sScript, sName, sIcon; + json jServerPlugins = ai_GetCampaignDbJson("plugins"); + json jPCPlugin, jPCPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + json jNewPCPlugins = JsonArray(); + json jServerPlugin = JsonArrayGet(jServerPlugins, nIndex); + while(JsonGetType(jServerPlugin) != JSON_TYPE_NULL) + { + bAllow = JsonGetInt(JsonArrayGet(jServerPlugin, 1)); + if(bAllow) + { + sName = JsonGetString(JsonArrayGet(jServerPlugin, 0)); + nCounter = 0; + jPCPlugin = JsonArrayGet(jPCPlugins, nCounter); + nJsonType = JsonGetType(jPCPlugin); + while(nJsonType != JSON_TYPE_NULL) + { + if(sName == JsonGetString(JsonArrayGet(jPCPlugin, 0))) + { + // Boolean - Add to widget. + bWidget = JsonGetInt(JsonArrayGet(jPCPlugin, 1)); + jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(bWidget)); + break; + } + jPCPlugin = JsonArrayGet(jPCPlugins, ++nCounter); + nJsonType = JsonGetType(jPCPlugin); + } + if(nJsonType == JSON_TYPE_NULL) + { + jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(FALSE)); + } + jNewPCPlugins = JsonArrayInsert(jNewPCPlugins, jServerPlugin); + } + jServerPlugin = JsonArrayGet(jServerPlugins, ++nIndex); + } + ai_SetAssociateDbJson(oPC, "pc", "plugins", jNewPCPlugins); + return jNewPCPlugins; +} +json ai_UpdatePluginsForDM(object oPC) +{ + int nJsonType, nCounter, nIndex, bWidget, bAllow; + string sName, sIcon, sDbName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jServerPlugins = ai_GetCampaignDbJson("plugins"); + ai_CheckDMDataAndInitialize(oPC); + json jDMPlugin, jDMPlugins = ai_GetCampaignDbJson("plugins", sDbName, AI_DM_TABLE); + json jNewDMPlugins = JsonArray(); + json jServerPlugin = JsonArrayGet(jServerPlugins, nIndex); + while(JsonGetType(jServerPlugin) != JSON_TYPE_NULL) + { + sName = JsonGetString(JsonArrayGet(jServerPlugin, 0)); + nCounter = 0; + jDMPlugin = JsonArrayGet(jDMPlugins, nCounter); + nJsonType = JsonGetType(jDMPlugin); + while(nJsonType != JSON_TYPE_NULL) + { + if(sName == JsonGetString(JsonArrayGet(jDMPlugin, 0))) + { + // Boolean - Add to widget. + bWidget = JsonGetInt(JsonArrayGet(jDMPlugin, 1)); + jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(bWidget)); + break; + } + jDMPlugin = JsonArrayGet(jDMPlugins, ++nCounter); + nJsonType = JsonGetType(jDMPlugin); + } + if(nJsonType == JSON_TYPE_NULL) + { + jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(FALSE)); + } + jNewDMPlugins = JsonArrayInsert(jNewDMPlugins, jServerPlugin); + jServerPlugin = JsonArrayGet(jServerPlugins, ++nIndex); + } + ai_SetCampaignDbJson("plugins", jNewDMPlugins, sDbName, AI_DM_TABLE); + return jNewDMPlugins; +} +void ai_StartupPlugins(object oPC) +{ + SetLocalInt(oPC, AI_STARTING_UP, TRUE); + int bUpdatePlugins; + string sScript; + json jPlugins; + if(GetIsDM(oPC)) jPlugins = ai_UpdatePluginsForDM(oPC); + else jPlugins = ai_UpdatePluginsForPC(oPC); + // We delete this so each mod can be added that legally loads. + DeleteLocalJson(GetModule(), AI_MONSTER_MOD_JSON); + int nIndex; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sScript = JsonGetString(JsonArrayGet(jPlugin, 0)); + ExecuteScript(sScript, oPC); + // -1 means if failed to load so lets make sure to remove it from the list. + if(GetLocalInt(oPC, AI_PLUGIN_SET) == -1) + { + jPlugins = JsonArrayDel(jPlugins, nIndex); + bUpdatePlugins = TRUE; + nIndex--; + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + if(bUpdatePlugins) ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins); + DeleteLocalInt(oPC, AI_STARTING_UP); +} diff --git a/src/module/nss/0i_menus.nss b/src/module/nss/0i_menus.nss new file mode 100644 index 0000000..8d6834c --- /dev/null +++ b/src/module/nss/0i_menus.nss @@ -0,0 +1,4823 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_menus +//////////////////////////////////////////////////////////////////////////////// + Include script for handling NUI menus. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "0i_associates" +// Maximum number of Plugins allowed on the players widget. +const int WIDGET_MAX_PLUGINS = 5; + +// Set one of the BTN_* "Widget" bitwise constants on oPlayer to bValid. +void ai_SetWidgetButton(object oPlayer, int nButton, object oAssociate, string sAssociateType, int bOn = TRUE); +// Return if nButton is set on oPlayer. Uses the BTN_* "Widget" bitwise constants. +int ai_GetWidgetButton(object oPlayer, int nButton, object oAssociate, string sAssociateType); +// Set one of the BTN_AI_* bitwise constants on oPlayer to bValid. +void ai_SetAIButton(object oPlayer, int nButton, object oAssociate, string sAssociateType, int bOn = TRUE); +// Return if nButton is set on oPlayer. Uses the BTN_AI_* "Widget" bitwise constants. +int ai_GetAIButton(object oPlayer, int nButton, object oAssociate, string sAssociateType); +// Set one of the BTN2_AI_* bitwise constants on oPlayer to bValid. +void ai_SetAIButton2(object oPlayer, int nButton, object oAssociate, string sAssociateType, int bOn = TRUE); +// Return if nButton is set on oPlayer. Uses the BTN2_AI_* "Widget" bitwise constants. +int ai_GetAIButton2(object oPlayer, int nButton, object oAssociate, string sAssociateType); +// Creates the json array required to build a companion drop down box for +// Animal Companions or Familiars. +// sCompanion2da should be either "hen_companion" or "hen_familiar". +json ai_CreateCompanionJson(object oPC, string sCompanion2da); +// Return any Metamagic or Domain attributes to place on a spell icon image. +string ai_GetSpellIconAttributes(object oCaster, int nMetaMagic, int nDomain); +// Creates the AI options menu. +void ai_CreateAIMainNUI(object oPC); +// Creates the AI options menu. +void ai_CreateAssociateCommandNUI(object oPC, object oAssociate); +// Creates an associates AI NUI. +void ai_CreateAssociateAINUI(object oPC, object oAssociate); +// Creates a widget for the player or associate. +void ai_CreateWidgetNUI(object oPC, object oAssociate); +// Creates the Loot filter menu. +void ai_CreateLootFilterNUI(object oPC, object oAssociate); +// Creates the Plugin Manager menu. +void ai_CreatePluginNUI(object oPC); +// Creates the Spell menu that selects the spells to go on the Spell Widget. +void ai_CreateQuickWidgetSelectionNUI(object oPC, object oAssociate); +// Creates the Spell menu that lets the player to select the associates castable spells. +void ai_CreateSpellMemorizationNUI(object oPC, object oAssociate); +// Creates the spell description menu so a player can see what a spell does. +// If nSpell > 0 then use that value for the spells description. +void ai_CreateDescriptionNUI(object oPC, json jSpell, int nSpell = 0); + +string ai_GetRandomTip() +{ + int nRoll; + if(AI_SERVER) nRoll = Random(26); + else nRoll = Random(46); + return Get2DAString("ai_messages", "Text", nRoll); +} +void ai_SetWidgetButton(object oPlayer, int nButton, object oAssociate, string sAssociateType, int bOn = TRUE) +{ + int nWidgetButtons = GetLocalInt(oAssociate, sWidgetButtonsVarname); + json jButtons = ai_GetAssociateDbJson(oPlayer, sAssociateType, "buttons"); + if(bOn) nWidgetButtons = nWidgetButtons | nButton; + else nWidgetButtons = nWidgetButtons & ~nButton; + SetLocalInt(oAssociate, sWidgetButtonsVarname, nWidgetButtons); + jButtons = JsonArraySet(jButtons, 0, JsonInt(nWidgetButtons)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons); +} +int ai_GetWidgetButton(object oPlayer, int nButton, object oAssociate, string sAssociateType) +{ + // This is the DM access switch that uses the same bitwise as the players + // to control what widget buttons they can use. + if(ai_GetDMWAccessButton(nButton)) return FALSE; + int nWidgetButtons = GetLocalInt(oAssociate, sWidgetButtonsVarname); + return nWidgetButtons & nButton; +} +void ai_SetAIButton(object oPlayer, int nButton, object oAssociate, string sAssociateType, int bOn = TRUE) +{ + int nAIButtons = GetLocalInt(oAssociate, sAIButtonsVarname); + json jButtons = ai_GetAssociateDbJson(oPlayer, sAssociateType, "buttons"); + if(bOn) nAIButtons = nAIButtons | nButton; + else nAIButtons = nAIButtons & ~nButton; + SetLocalInt(oAssociate, sAIButtonsVarname, nAIButtons); + jButtons = JsonArraySet(jButtons, 1, JsonInt(nAIButtons)); + ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons); +} +int ai_GetAIButton(object oPlayer, int nButton, object oAssociate, string sAssociateType) +{ + // This is the DM access switch that uses the same bitwise as the players + // to control what AI widget buttons they can use. + if(ai_GetDMAIAccessButton(nButton)) return FALSE; + int nAIButtons = GetLocalInt(oAssociate, sAIButtonsVarname); + return nAIButtons & nButton; +} +json ai_CreateAIScriptJson(object oPC) +{ + json jScript = JsonArrayInsert(JsonArray(), NuiComboEntry("", 0)); + int nNth = 1; + string sScript = ResManFindPrefix("ai_a_", RESTYPE_NCS, nNth); + while(sScript != "") + { + jScript = JsonArrayInsert(jScript, NuiComboEntry(sScript, nNth)); + sScript = ResManFindPrefix("ai_a_", RESTYPE_NCS, ++nNth); + } + return jScript; +} +json ai_CreateCompanionJson(object oPC, string sCompanion2da) +{ + int nCnt, nMaxRowCount = Get2DARowCount(sCompanion2da); + string sName; + json jCompanion = JsonArray(); + while(nCnt < nMaxRowCount) + { + sName = GetStringByStrRef(StringToInt(Get2DAString(sCompanion2da, "STRREF", nCnt))); + jCompanion = JsonArrayInsert(jCompanion, NuiComboEntry(sName, nCnt++)); + } + return JsonArrayInsert(jCompanion, NuiComboEntry("Random", nCnt)); +} +string ai_GetSpellIconAttributes(object oCaster, int nMetaMagic, int nDomain) +{ + string sAttributeText; + if(nMetaMagic != METAMAGIC_ANY && nMetaMagic != METAMAGIC_NONE) + { + if(nMetaMagic == METAMAGIC_EXTEND) sAttributeText = "X"; + if(nMetaMagic == METAMAGIC_EMPOWER) sAttributeText = "P"; + if(nMetaMagic == METAMAGIC_MAXIMIZE) sAttributeText = "M"; + if(nMetaMagic == METAMAGIC_QUICKEN) sAttributeText = "Q"; + if(nMetaMagic == METAMAGIC_SILENT) sAttributeText = "I"; + if(nMetaMagic == METAMAGIC_STILL) sAttributeText = "T"; + } + else sAttributeText = ""; + if(nDomain > 0) sAttributeText += "D"; + return sAttributeText; +} +void ai_CreateAIMainNUI(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int nMonsterAI = (ResManGetAliasFor("ai_default", RESTYPE_NCS) != ""); + int nAssociateAI = (ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != ""); + string sText = " [Single player]"; + if(AI_SERVER) sText = " [Server]"; + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, PHILOS_VERSION + sText, "lbl_version ", 510.0f, 20.0f, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 101 + jRow = CreateLabel(JsonArray(), "", "lbl_ai_info", 510.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 500 / 129 + jRow = CreateButton(JsonArray(), "Plugin Manager", "btn_plugin_manager", 120.0f, 20.0f, -1.0, "btn_plugin_manager_tooltip"); + if(nAssociateAI) jRow = CreateButtonSelect(jRow, "Associate Widgets", "btn_toggle_assoc_widget", 140.0f, 20.0f, "btn_assoc_widget_tooltip"); + jRow = CreateButtonSelect(jRow, "Action Ghost Mode", "btn_action_ghost", 160.0f, 20.0f, "btn_action_ghost_tooltip"); + jRow = CreateButtonSelect(jRow, "Effect Icons", "btn_effect_icon", 100.0f, 20.0f, "btn_effect_icon_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 500 / 157 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "MODULE RULES", "lbl_ai_rules", 200.0f, 20.0f, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 157.0; + // Row 5 ******************************************************************* 500 / --- (28) + // Make the AI options a Group. + json jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_max_henchman", 2, FALSE, 30.0f, 20.0f, "txt_max_henchman_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "Max number of henchmen that is allowed in your party.", "lbl_max_hench", 416.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_max_henchman_tooltip"); + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_xp_scale", 3, FALSE, 40.0f, 20.0f, "txt_xp_scale_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "Modules experience scale.", "lbl_xp_scale", 175.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_xp_scale_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " scale to party.", "chbx_party_scale", 150.0, 20.0, "chbx_party_scale_tooltip"); + jGroupRow = CreateButton(jGroupRow, "Default", "btn_default_xp", 70.0f, 20.0f, -1.0, "btn_default_xp_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 78.0; + if(nMonsterAI || nAssociateAI) + { + jGroupRow = CreateCheckBox(JsonArray(), " Creatures will use advanced combat movement.", "chbx_advanced_movement", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Use item level restrictions for creatures [Default is off].", "chbx_ilr", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Creatures can use the skill Use Magic Device.", "chbx_umd", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Creatures can use Healing kits.", "chbx_use_healingkits", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Moral checks, wounded creatures may flee during combat.", "chbx_moral", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), " Spells the AI will not use:", "lbl_restrict_spells", 190.0, 20.0, NUI_HALIGN_LEFT); + jGroupRow = CreateCheckBox(jGroupRow, " Darkness", "chbx_darkness", 90.0, 20.0, "chbx_darkness_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " Dispels", "chbx_dispels", 90.0, 20.0, "chbx_dispels_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " Time Stop", "chbx_timestop", 90.0, 20.0, "chbx_timestop_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 196.0; + } + if(nMonsterAI) + { + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_ai_difficulty", 3, FALSE, 40.0f, 20.0f, "txt_ai_difficulty_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "% chance monsters will attack the weakest target.", "lbl_ai_difficulty", 406.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_ai_difficulty_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_perception_distance", 2, FALSE, 35.0f, 20.0f, "txt_perception_distance_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "meters is the distance a monster can respond to allies.", "lbl_perception_distance", 411.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "txt_perception_distance_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can prebuff before combat starts.", "chbx_buff_monsters", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can use summons before combat starts.", "chbx_buff_summons", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can use tactics (ambush, defensive, flanker, etc).", "chbx_ambush_monsters", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "Add ", "lbl_inc_enc", 30.0, 20.0, NUI_HALIGN_LEFT, 0, -1.0); + jGroupRow = CreateTextEditBox(jGroupRow, "sPlaceHolder", "txt_inc_enc", 4, FALSE, 55.0f, 20.0f, "txt_inc_enc_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "monsters per spawned encounter monster.", "lbl_inc_enc", 357.0, 20.0, NUI_HALIGN_LEFT, NUI_VALIGN_MIDDLE, 0.0, "txt_inc_enc_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_inc_hp", 3, FALSE, 40.0f, 20.0f, "txt_inc_hp_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "% increase in all monster's hitpoints.", "lbl_inc_hp", 406.0, 20.0, NUI_HALIGN_LEFT); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "***** WARNING! The options below may break the module! *****", "lbl_warning", 450.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can wander upto ", "chbx_wander", 220.0, 20.0, "chbx_warning_tooltip"); + jGroupRow = CreateTextEditBox(jGroupRow, "sPlaceHolder", "txt_wander_distance", 2, FALSE, 35.0f, 20.0f, "chbx_warning_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "meters and ", "lbl_wander_distance", 80.0f, 20.0f, NUI_HALIGN_LEFT, NUI_VALIGN_MIDDLE, 0.0, "chbx_warning_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, "open doors.", "chbx_open_doors", 100.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can summon companions.", "chbx_companions", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Summoned associates to remain after masters death.", "chbx_perm_assoc", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Make enemy corpses remain.", "chbx_corpses_stay", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_perc_dist", 450.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "lbl_perc_dist_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 336.0; + } + jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + json jLocations = ai_GetAssociateDbJson(oPC, "pc", "locations"); + jLocations = JsonObjectGet(jLocations, AI_MAIN_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, AI_MAIN_NUI, sName + " PEPS Main Menu", + fX, fY, 534.0f, fHeight, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArray(); + jData = JsonArrayInsert(jData, JsonString(ObjectToString(oPC))); + NuiSetUserData(oPC, nToken, jData); + object oModule = GetModule(); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 - Version label. + // Row 2 + int nUsing; + // Check the monster AI. + string sLocation = ResManGetAliasFor("ai_default", RESTYPE_NCS); + if(sLocation != "") + { + nUsing = TRUE; + string sLocation = ResManGetAliasFor("nw_c2_default1", RESTYPE_NCS); + if(sLocation != "OVERRIDE:" && sLocation != "PATCH:peps" && sLocation != "DEVELOPMENT:") nUsing = FALSE; + if(nUsing) sText = "Monster AI working"; + else sText = "Monster AI not working"; + } + else sText = "Monster AI not loaded"; + // Check the associate AI. + sLocation = ResManGetAliasFor("ai_a_default", RESTYPE_NCS); + if(sLocation != "") + { + nUsing = TRUE; + string sLocation = ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS); + if(sLocation != "OVERRIDE:" && sLocation != "PATCH:peps" && sLocation != "DEVELOPMENT:") nUsing = FALSE; + if(nUsing) sText += ", Associate AI working"; + else sText += ", Associate AI not working"; + } + else sText += ", Associate AI not loaded"; + // Check for PRC. + sLocation = ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS); + if(sLocation != "") sText += ", PRC loaded."; + else + { + // Check the player AI. + sLocation = ResManGetAliasFor("xx_pc_1_hb", RESTYPE_NCS); + if(sLocation != "") sText += ", Player AI loaded."; + else sText += ", Player AI not loaded."; + } + NuiSetBind(oPC, nToken, "lbl_ai_info_label", JsonString(sText)); + // Row 3 + NuiSetBind(oPC, nToken, "btn_plugin_manager_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_plugin_manager_tooltip", JsonString(" Manages external executable scripts.")); + if(nAssociateAI) + { + NuiSetBind(oPC, nToken, "btn_toggle_assoc_widget_event", JsonBool(TRUE)); + int bWidgetOn = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, OBJECT_INVALID, "pc"); + NuiSetBind(oPC, nToken, "btn_toggle_assoc_widget", JsonBool(bWidgetOn)); + NuiSetBind(oPC, nToken, "btn_assoc_widget_tooltip", JsonString(" Turns On/Off all associate widgets.")); + } + int bActionGhost = ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST); + NuiSetBind(oPC, nToken, "btn_action_ghost", JsonBool (bActionGhost)); + NuiSetBind(oPC, nToken, "btn_action_ghost_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_action_ghost_tooltip", JsonString(" Allows associates to move through creatures while in command mode.")); + int bEffectIcon = ai_GetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT); + NuiSetBind(oPC, nToken, "btn_effect_icon", JsonBool (bEffectIcon)); + NuiSetBind(oPC, nToken, "btn_effect_icon_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_effect_icon_tooltip", JsonString(" When on sends effect icon reports to the chat screen.")); + // Row 3 Label for AI RULES + // Row 4 + NuiSetBind(oPC, nToken, "txt_max_henchman", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_MAX_HENCHMAN)))); + NuiSetBindWatch (oPC, nToken, "txt_max_henchman", TRUE); + NuiSetBind(oPC, nToken, "txt_max_henchman_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_max_henchman_tooltip", JsonString(" Set max number of henchman allowed (1-12).")); + NuiSetBind(oPC, nToken, "txt_xp_scale", JsonString(IntToString(GetModuleXPScale()))); + NuiSetBindWatch (oPC, nToken, "txt_xp_scale", TRUE); + NuiSetBind(oPC, nToken, "txt_xp_scale_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_xp_scale_tooltip", JsonString(" Set the modules XP scale (0 - 200) Normal D&D is 10.")); + NuiSetBind(oPC, nToken, "chbx_party_scale_check", JsonBool(GetLocalInt(oModule, AI_RULE_PARTY_SCALE))); + NuiSetBindWatch(oPC, nToken, "chbx_party_scale_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_party_scale_event", JsonBool(TRUE)); + sText = IntToString(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP)); + NuiSetBind(oPC, nToken, "chbx_party_scale_tooltip", JsonString(" PEPS adjusts your XP based on party size from (" + sText + ").")); + NuiSetBind(oPC, nToken, "btn_default_xp_event", JsonBool(TRUE)); + sText = IntToString(GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE)); + NuiSetBind(oPC, nToken, "btn_default_xp_tooltip", JsonString(" Reset the Modules XP to (" + sText + ").")); + NuiSetBind(oPC, nToken, "chbx_warning_tooltip", JsonString(" ** This will break some modules! ** See Readme for issues!")); + if(nMonsterAI) + { + NuiSetBind(oPC, nToken, "txt_ai_difficulty", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_AI_DIFFICULTY)))); + NuiSetBindWatch(oPC, nToken, "txt_ai_difficulty", TRUE); + NuiSetBind(oPC, nToken, "txt_ai_difficulty_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_buff_monsters_check", JsonBool(GetLocalInt(oModule, AI_RULE_BUFF_MONSTERS))); + NuiSetBindWatch(oPC, nToken, "chbx_buff_monsters_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_monsters_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_buff_summons_check", JsonBool(GetLocalInt(oModule, AI_RULE_PRESUMMON))); + NuiSetBindWatch(oPC, nToken, "chbx_buff_summons_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_summons_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_ambush_monsters_check", JsonBool(GetLocalInt(oModule, AI_RULE_AMBUSH))); + NuiSetBindWatch(oPC, nToken, "chbx_ambush_monsters_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ambush_monsters_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_companions_check", JsonBool(GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS))); + NuiSetBindWatch(oPC, nToken, "chbx_companions_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_companions_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_perm_assoc_check", JsonBool(GetLocalInt(oModule, AI_RULE_PERM_ASSOC))); + string sModuleName = GetModuleName(); + if(!GetLocalInt(oModule, AI_USING_PRC) && + (sModuleName != "Neverwinter Nights - Infinite Dungeons" || + sModuleName != "Infinite Dungeons [PRC8]")) + { + NuiSetBindWatch(oPC, nToken, "chbx_perm_assoc_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_perm_assoc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_corpses_stay_check", JsonBool(GetLocalInt(oModule, AI_RULE_CORPSES_STAY))); + NuiSetBindWatch(oPC, nToken, "chbx_corpses_stay_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_corpses_stay_event", JsonBool(TRUE)); + } + NuiSetBind(oPC, nToken, "txt_perception_distance", JsonString(FloatToString(GetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE), 0, 0))); + NuiSetBindWatch(oPC, nToken, "txt_perception_distance", TRUE); + NuiSetBind(oPC, nToken, "txt_perception_distance_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_perception_distance_tooltip", JsonString(" Range [10 to 60 meters] from the player.")); + NuiSetBindWatch(oPC, nToken, "lbl_perc_dist", TRUE); + int nPercDist = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE); + if(nPercDist < 8 || nPercDist > 11) + { + nPercDist = 11; + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, 11); + } + if(nPercDist == 8) sText = " Monster perception: Short [10 Sight / 10 Listen]"; + else if(nPercDist == 9) sText = " Monster perception: Medium [20 Sight / 20 Listen]"; + else if(nPercDist == 10) sText = " Monster perception: Long [35 Sight / 20 Listen]"; + else sText = " Monster perception: Default [Monster's default values]"; + NuiSetBind(oPC, nToken, "lbl_perc_dist_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "lbl_perc_dist_tooltip", JsonString(" Use the mouse wheel to change values.")); + int bWander = GetLocalInt(oModule, AI_RULE_WANDER); + NuiSetBind(oPC, nToken, "chbx_wander_check", JsonBool(bWander)); + NuiSetBindWatch(oPC, nToken, "chbx_wander_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_wander_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_wander_distance", JsonString(FloatToString(GetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE), 0, 0))); + NuiSetBindWatch(oPC, nToken, "txt_wander_distance", TRUE); + NuiSetBind(oPC, nToken, "txt_wander_distance_event", JsonBool(bWander)); + NuiSetBind(oPC, nToken, "chbx_open_doors_check", JsonBool(GetLocalInt(oModule, AI_RULE_OPEN_DOORS))); + NuiSetBindWatch(oPC, nToken, "chbx_open_doors_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_open_doors_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_open_doors_tooltip", JsonString(" This allows monsters to open doors to hunt you down!")); + NuiSetBind(oPC, nToken, "txt_inc_enc_tooltip", JsonString(" Spawns one extra monster per counter above 1. Adds value to counter per encounter monster spawned.")); + NuiSetBind(oPC, nToken, "txt_inc_enc", JsonString(FloatToString(GetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS), 0, 2))); + NuiSetBindWatch(oPC, nToken, "txt_inc_enc", TRUE); + NuiSetBind(oPC, nToken, "txt_inc_enc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_inc_hp", JsonString(IntToString(GetLocalInt(oModule, AI_INCREASE_MONSTERS_HP)))); + NuiSetBindWatch(oPC, nToken, "txt_inc_hp", TRUE); + NuiSetBind(oPC, nToken, "txt_inc_hp_event", JsonBool(TRUE)); + } + if(nMonsterAI || nAssociateAI) + { + NuiSetBind(oPC, nToken, "chbx_moral_check", JsonBool(GetLocalInt(oModule, AI_RULE_MORAL_CHECKS))); + NuiSetBindWatch (oPC, nToken, "chbx_moral_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_moral_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_advanced_movement_check", JsonBool(GetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT))); + NuiSetBindWatch (oPC, nToken, "chbx_advanced_movement_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_advanced_movement_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_ilr_check", JsonBool(GetLocalInt(oModule, AI_RULE_ILR))); + NuiSetBindWatch (oPC, nToken, "chbx_ilr_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ilr_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_umd_check", JsonBool(GetLocalInt(oModule, AI_RULE_ALLOW_UMD))); + NuiSetBindWatch (oPC, nToken, "chbx_umd_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_umd_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_use_healingkits_check", JsonBool(GetLocalInt(oModule, AI_RULE_HEALERSKITS))); + NuiSetBindWatch (oPC, nToken, "chbx_use_healingkits_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_use_healingkits_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_darkness_check", JsonBool(ai_SpellRestricted(SPELL_DARKNESS))); + NuiSetBindWatch (oPC, nToken, "chbx_darkness_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_darkness_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_darkness_tooltip", JsonString(" AI will not use the Darkness spell in combat.")); + NuiSetBind(oPC, nToken, "chbx_dispels_check", JsonBool(ai_SpellRestricted(SPELL_DISPEL_MAGIC))); + NuiSetBindWatch (oPC, nToken, "chbx_dispels_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_dispels_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_dispels_tooltip", JsonString(" AI will not use any of the Dispel spells in combat.")); + NuiSetBind(oPC, nToken, "chbx_timestop_check", JsonBool(ai_SpellRestricted(SPELL_TIME_STOP))); + NuiSetBindWatch (oPC, nToken, "chbx_timestop_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_timestop_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_timestop_tooltip", JsonString(" AI will not use the Time Stop spell in combat.")); + } +} +void ai_CreateAssociateCommandNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int bRight, bLeft; + int bIsPC = ai_GetIsCharacter(oAssociate); + int bUsingPCAI = ResManGetAliasFor("xx_pc_1_hb", RESTYPE_NCS) != ""; + int bUsingHenchAI = ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS) != ""; + float fHeight = 73.0; + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 73 + json jRow = JsonArray(); + json jCol = JsonArray(); + // If all the AI buttons are blocked then don't load the menu. + if(GetLocalInt(GetModule(), sDMAIAccessVarname) != 203423743) + { + if(bIsPC) + { + if(bUsingPCAI || !AI_SERVER) + { + if(bUsingPCAI) + { + jRow = CreateButton(jRow, "AI Menu", "btn_ai_menu", 232.0, 20.0, -1.0, "btn_ai_menu_tooltip"); + } + if(!AI_SERVER) + { + jRow = CreateButton(jRow, "Main Menu", "btn_main_menu", 232.0, 20.0, -1.0, "btn_main_menu_tooltip"); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + } + else + { + if(bUsingHenchAI) + { + jRow = CreateButton(jRow, "AI Menu", "btn_ai_menu", 232.0, 20.0, -1.0, "btn_ai_menu_tooltip"); + } + jRow = CreateButtonSelect(jRow, "", "btn_widget_onoff", 232.0, 20.0, "btn_widget_onoff_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + } + // Row 2 ******************************************************************* 500 / 101 + jRow = JsonArray(); + jRow = CreateButtonSelect(jRow, "Lock Widget", "btn_widget_lock", 154.0, 20.0, "btn_widget_lock_tooltip"); + jRow = CreateButton(jRow, "Copy Settings", "btn_copy_settings", 154.0, 20.0, -1.0, "btn_copy_settings_tooltip"); + jRow = CreateButtonSelect(jRow, "Vertical Widget", "btn_vertical_widget", 154.0, 20.0, "btn_vertical_widget_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 500 / 129 + bRight = !ai_GetDMWAccessButton(BTN_CMD_ACTION); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_GUARD); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "", "btn_cmd_action", 200.0, 20.0, -1.0, "btn_cmd_action_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_action", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "", "btn_cmd_guard", 200.0, 20.0, -1.0, "btn_cmd_guard_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_guard", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 4 ******************************************************************* 500 / 157 + jRow = JsonArray(); + bRight = !ai_GetDMWAccessButton(BTN_CMD_HOLD); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_ATTACK); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "", "btn_cmd_hold", 200.0, 20.0, -1.0, "btn_cmd_hold_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_hold", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "", "btn_cmd_attack", 200.0, 20.0, -1.0, "btn_cmd_attack_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_attack", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 5 ******************************************************************* 500 / 213 + bRight = !ai_GetDMWAccessButton(BTN_CMD_FOLLOW); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_FOLLOW_TARGET); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "", "btn_cmd_follow", 200.0, 20.0, -1.0, "btn_cmd_follow_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_follow", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Select follow target", "btn_follow_target", 200.0, 20.0, -1.0, "btn_follow_target_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_follow_target", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 6 ******************************************************************* 500 / 185 + if(bIsPC) + { + bRight = !ai_GetDMWAccessButton(BTN_CMD_SEARCH); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_STEALTH); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "All Search Mode", "btn_cmd_search", 200.0, 20.0, -1.0, "btn_cmd_search_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_search", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "All Stealth Mode", "btn_cmd_stealth", 200.0, 20.0, -1.0, "btn_cmd_stealth_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_stealth", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + } + // Row 7 ******************************************************************* 500 / 241 + bRight = !ai_GetDMWAccessButton(BTN_CMD_AI_SCRIPT); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_PLACE_TRAP); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Combat Tactics", "btn_cmd_ai_script", 200.0, 20.0, -1.0, "btn_cmd_ai_script_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_ai_script", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Place a Trap", "btn_cmd_place_trap", 200.0, 20.0, -1.0, "btn_cmd_place_trap_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_place_trap", 25.0, 20.0); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 8 ******************************************************************* 500 / --- + int bMemorize = ai_GetIsSpellCaster(oAssociate); + int bSpellbook = ai_GetIsSpellBookRestrictedCaster(oAssociate); + bRight = !ai_GetDMWAccessButton(BTN_CMD_SPELL_WIDGET); + bLeft = !ai_GetDMWAccessButton(BTN_DM_CMD_MEMORIZE); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Set Quick Widget", "btn_quick_widget", 200.0, 20.0, -1.0, "btn_quick_widget_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_quick_widget", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) // Memorizes their spells. + { + if(bMemorize == 2 && bSpellbook) + { + jRow = CreateButton(jRow, "Memorize Spells", "btn_spell_memorize", 114.0, 20.0, -1.0, "btn_spell_memorize_tooltip"); + jRow = CreateButton(jRow, "Known Spells", "btn_spell_known", 110.0, 20.0, -1.0, "btn_spell_known_tooltip"); + } + else if(bMemorize == 2) + { + jRow = CreateButton(jRow, "Set Memorize Spells", "btn_spell_memorize", 200.0, 20.0, -1.0, "btn_spell_memorize_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_1", 25.0, 20.0); + } + else if(bSpellbook && !ai_GetIsCharacter(oAssociate)) + { + jRow = CreateButton(jRow, "Set Known Spells", "btn_spell_known", 200.0, 20.0, -1.0, "btn_spell_known_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_1", 25.0, 20.0); + } + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 9 ******************************************************************* 500 / 269 + bRight = !ai_GetDMWAccessButton(BTN_BUFF_SHORT); + bLeft = !ai_GetDMWAccessButton(BTN_BUFF_LONG); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Cast Short Buff spells", "btn_buff_short", 200.0, 20.0, -1.0, "btn_buff_short_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_short", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Cast Long Buff spells", "btn_buff_long", 200.0, 20.0, -1.0, "btn_buff_long_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_long", 25.0, 20.0); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 10 ******************************************************************* 500 / 297 + bRight = !ai_GetDMWAccessButton(BTN_BUFF_ALL); + bLeft = !ai_GetDMWAccessButton(BTN_BUFF_REST); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Cast All Buff spells", "btn_buff_all", 200.0, 20.0, -1.0, "btn_buff_all_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_all", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Buff after resting", "btn_buff_rest", 200.0, 20.0, -1.0, "btn_buff_rest_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_rest", 25.0, 20.0); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 11 ******************************************************************* 500 / 325 + bRight = !ai_GetDMWAccessButton(BTN_CMD_JUMP_TO); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_GHOST_MODE); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "", "btn_jump_to", 200.0, 20.0, -1.0, "btn_jump_to"); + jRow = CreateCheckBox(jRow, "", "chbx_jump_to", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Ghost Mode", "btn_ghost_mode", 200.0, 20.0, -1.0, "btn_ghost_mode_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ghost_mode", 25.0, 20.0); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 12 ****************************************************************** 500 / 353 + bRight = !ai_GetDMWAccessButton(BTN_CMD_CAMERA); + bLeft = !ai_GetDMWAccessButton(BTN_CMD_INVENTORY); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Toggle Camera Focus", "btn_camera", 200.0, 20.0, -1.0, "btn_camera_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_camera", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Open/Close Inventory", "btn_inventory", 200.0, 20.0, -1.0, "btn_inventory_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_inventory", 25.0, 20.0); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 13 ******************************************************************* 500 / --- + int bFamiliar = GetHasFeat(FEAT_SUMMON_FAMILIAR, oAssociate, TRUE); + if(!ai_GetDMWAccessButton(BTN_CMD_FAMILIAR) && bFamiliar) + { + jRow = JsonArray(); + jRow = CreateLabel(jRow, "", "lbl_familiar_type", 225.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "", "lbl_familiar_name", 225.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + // Row 14 ******************************************************************* 500 / --- + jRow = JsonArray(); + jRow = CreateCombo(jRow, ai_CreateCompanionJson(oPC, "hen_familiar"), "cmb_familiar", 200.0, 20.0); + jRow = CreateCheckBox(jRow, "", "chbx_familiar", 25.0, 20.0); + jRow = CreateTextEditBox(jRow, "txtbox", "txt_familiar_name", 50, FALSE, 178.0, 20.0); + jRow = CreateButton(jRow, "", "btn_familiar_name", 55.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 15 ******************************************************************* 500 / --- + int bCompanion = GetHasFeat(FEAT_ANIMAL_COMPANION, oAssociate, TRUE); + if(!ai_GetDMWAccessButton(BTN_CMD_COMPANION) && bCompanion) + { + jRow = JsonArray(); + jRow = CreateLabel(jRow, "", "lbl_companion_type", 225.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "", "lbl_companion_name", 225.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + // Row 16 ******************************************************************* 500 / --- + jRow = JsonArray(); + jRow = CreateCombo(jRow, ai_CreateCompanionJson(oPC, "hen_companion"), "cmb_companion", 200.0, 20.0); + jRow = CreateCheckBox(jRow, "", "chbx_companion", 25.0, 20.0); + jRow = CreateTextEditBox(jRow, "txtbox", "txt_companion_name", 50, FALSE, 178.0, 20.0); + jRow = CreateButton(jRow, "", "btn_companion_name", 55.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + } + // Row 17+ ****************************************************************** 500 / --- + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jPCPlugins; + if(bIsPC) + { + jPCPlugins = ai_UpdatePluginsForPC(oPC); + // Set the plugins the player can use. + int nIndex; + string sButton, sName; + json jPlugin = JsonArrayGet(jPCPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + jRow = JsonArray(); + sButton = IntToString(nIndex); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(jRow, sName, "btn_plugin_" + sButton, 200.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0, "chbx_plugin_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jPlugin = JsonArrayGet(jPCPlugins, ++nIndex); + if(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(jRow, sName, "btn_plugin_" + sButton, 200.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0, "chbx_plugin_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + else + { + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + break; + } + jPlugin = JsonArrayGet(jPCPlugins, ++nIndex); + } + } + // Row 18 ****************************************************************** 500 / --- + jRow = JsonArray(); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "", "lbl_info_1", 475.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_COMMAND_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_COMMAND_NUI, sName + " Command Menu", + fX, fY, 500.0, fHeight + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Get which buttons are activated. + int bAIWidgetLock = ai_GetWidgetButton(oPC, BTN_WIDGET_LOCK, oAssociate, sAssociateType); + int bCmdAction = ai_GetWidgetButton(oPC, BTN_CMD_ACTION, oAssociate, sAssociateType); + int bCmdGuard = ai_GetWidgetButton(oPC, BTN_CMD_GUARD, oAssociate, sAssociateType); + int bCmdHold = ai_GetWidgetButton(oPC, BTN_CMD_HOLD, oAssociate, sAssociateType); + int bCmdSearch = ai_GetWidgetButton(oPC, BTN_CMD_SEARCH, oAssociate, sAssociateType); + int bCmdStealth = ai_GetWidgetButton(oPC, BTN_CMD_STEALTH, oAssociate, sAssociateType); + int bCmdAttack = ai_GetWidgetButton(oPC, BTN_CMD_ATTACK, oAssociate, sAssociateType); + int bCmdFollow = ai_GetWidgetButton(oPC, BTN_CMD_FOLLOW, oAssociate, sAssociateType); + int bFollowTarget = ai_GetAIButton(oPC, BTN_AI_FOLLOW_TARGET, oAssociate, sAssociateType); + int bCmdAIScript = ai_GetWidgetButton(oPC, BTN_CMD_AI_SCRIPT, oAssociate, sAssociateType); + int bCmdPlacetrap = ai_GetWidgetButton(oPC, BTN_CMD_PLACE_TRAP, oAssociate, sAssociateType); + int bSpellWidget = ai_GetWidgetButton(oPC, BTN_CMD_SPELL_WIDGET, oAssociate, sAssociateType); + int bBuffRest = ai_GetWidgetButton(oPC, BTN_BUFF_REST, oAssociate, sAssociateType); + int bBuffShort = ai_GetWidgetButton(oPC, BTN_BUFF_SHORT, oAssociate, sAssociateType); + int bBuffLong = ai_GetWidgetButton(oPC, BTN_BUFF_LONG, oAssociate, sAssociateType); + int bBuffAll = ai_GetWidgetButton(oPC, BTN_BUFF_ALL, oAssociate, sAssociateType); + int bJumpTo = ai_GetWidgetButton(oPC, BTN_CMD_JUMP_TO, oAssociate, sAssociateType); + int bGhostMode = ai_GetWidgetButton(oPC, BTN_CMD_GHOST_MODE, oAssociate, sAssociateType); + int bCamera = ai_GetWidgetButton(oPC, BTN_CMD_CAMERA, oAssociate, sAssociateType); + int bInventory = ai_GetWidgetButton(oPC, BTN_CMD_INVENTORY, oAssociate, sAssociateType); + int bBtnFamiliar = ai_GetWidgetButton(oPC, BTN_CMD_FAMILIAR, oAssociate, sAssociateType); + int bBtnCompanion = ai_GetWidgetButton(oPC, BTN_CMD_COMPANION, oAssociate, sAssociateType); + int bVertical = ai_GetWidgetButton(oPC, BTN_WIDGET_VERTICAL, oAssociate, sAssociateType); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArray(); + jData = JsonArrayInsert(jData, JsonString(ObjectToString(oAssociate))); + NuiSetUserData(oPC, nToken, jData); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + string sText; + // Row 1 + // If all the AI buttons are blocked then don't load the menu. + if(GetLocalInt(GetModule(), sDMAIAccessVarname) != 203423743) + { + if(bIsPC) + { + if(bUsingPCAI) + { + NuiSetBind(oPC, nToken, "btn_ai_menu_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_menu_tooltip", JsonString(" " + sName + " AI options")); + } + NuiSetBind(oPC, nToken, "btn_copy_settings_event", JsonBool (TRUE)); + sText = " Copy AI and command settings for one creature to others."; + NuiSetBind(oPC, nToken, "btn_copy_settings_tooltip", JsonString(sText)); + if(!AI_SERVER) + { + NuiSetBind(oPC, nToken, "btn_main_menu_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_main_menu_tooltip", JsonString(" Module Options")); + } + } + else + { + if(bUsingHenchAI) + { + NuiSetBind(oPC, nToken, "btn_ai_menu_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_menu_tooltip", JsonString(" " + sName + " AI options")); + } + NuiSetBind(oPC, nToken, "btn_copy_settings_event", JsonBool (TRUE)); + sText = " Copy AI and command settings for one creature to others."; + NuiSetBind(oPC, nToken, "btn_copy_settings_tooltip", JsonString(sText)); + string sText2; + if(ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType)) + { + sText = "Off"; sText2 = "on"; + NuiSetBind(oPC, nToken, "btn_widget_onoff", JsonBool(FALSE)); + } + else + { + sText = "On"; sText2 = "off"; + NuiSetBind(oPC, nToken, "btn_widget_onoff", JsonBool(TRUE)); + } + NuiSetBind(oPC, nToken, "btn_widget_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_onoff_label", JsonString("Widget " + sText)); + NuiSetBind(oPC, nToken, "btn_widget_onoff_tooltip", JsonString( + " Turn " + sName + " widget " + sText2)); + } + } + // Row 2 + NuiSetBind(oPC, nToken, "btn_widget_lock_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_lock", JsonBool(bAIWidgetLock)); + NuiSetBind(oPC, nToken, "btn_widget_lock_tooltip", JsonString( + " Locks " + sName + " widget to the current location.")); + NuiSetBind(oPC, nToken, "btn_widget_size_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_size_tooltip", JsonString( + " Adjusts the size of " + sName + " widget buttons")); + NuiSetBind(oPC, nToken, "btn_vertical_widget_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_vertical_widget", JsonBool(bVertical)); + NuiSetBind(oPC, nToken, "btn_vertical_widget_tooltip", JsonString( + " " + sName + " widget will display vertically")); + // Row 3 + NuiSetBind(oPC, nToken, "chbx_cmd_action_check", JsonBool (bCmdAction)); + NuiSetBindWatch(oPC, nToken, "chbx_cmd_action_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_action_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_action_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_guard_check", JsonBool (bCmdGuard)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_guard_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_guard_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_guard_event", JsonBool (TRUE)); + // Row 4 + NuiSetBind(oPC, nToken, "chbx_cmd_hold_check", JsonBool (bCmdHold)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_hold_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_hold_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_hold_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_attack_check", JsonBool (bCmdAttack)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_attack_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_attack_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_attack_event", JsonBool (TRUE)); + // Row 5 + NuiSetBind(oPC, nToken, "chbx_cmd_follow_check", JsonBool (bCmdFollow)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_follow_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_follow_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_follow_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_follow_target_check", JsonBool (bFollowTarget)); + NuiSetBindWatch (oPC, nToken, "chbx_follow_target_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_follow_target_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_follow_target_event", JsonBool (TRUE)); + // Row 6 + if(bIsPC) + { + NuiSetBind(oPC, nToken, "chbx_cmd_search_check", JsonBool (bCmdSearch)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_search_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_search_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_search_event", JsonBool (TRUE)); + if(ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_SEARCH)) sText = " leave "; + else sText = " enter "; + NuiSetBind(oPC, nToken, "btn_cmd_search_tooltip", JsonString(" Everyone" + sText + "search mode")); + NuiSetBind(oPC, nToken, "chbx_cmd_stealth_check", JsonBool (bCmdStealth)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_stealth_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_stealth_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_stealth_event", JsonBool (TRUE)); + if(ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_STEALTH)) sText = " leave "; + else sText = " enter "; + NuiSetBind(oPC, nToken, "btn_cmd_stealth_tooltip", JsonString(" Everyone" + sText + "stealth mode")); + } + // Command labels + if(bIsPC) sText = " All "; + else sText = " "; + NuiSetBind(oPC, nToken, "btn_cmd_action_label", JsonString(sText + "Action")); + NuiSetBind(oPC, nToken, "btn_cmd_guard_label", JsonString(sText + "Guard Mode")); + NuiSetBind(oPC, nToken, "btn_cmd_hold_label", JsonString(sText + "Hold Mode")); + NuiSetBind(oPC, nToken, "btn_cmd_attack_label", JsonString(sText + "Normal Mode")); + NuiSetBind(oPC, nToken, "btn_cmd_follow_label", JsonString(sText + "Follow Mode")); + NuiSetBind(oPC, nToken, "btn_follow_target_label", JsonString(" Follow Target")); + float fRange = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + + StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate))); + string sRange = FloatToString(fRange, 0, 0); + if(bIsPC) + { + sText = " All associates"; + NuiSetBind(oPC, nToken, "btn_cmd_follow_tooltip", JsonString(sText + " enter follow mode")); + } + else + { + sText = " " + GetName(oAssociate); + NuiSetBind(oPC, nToken, "btn_cmd_follow_tooltip", JsonString(sText + " enter follow mode [" + sRange + " meters]")); + } + NuiSetBind(oPC, nToken, "btn_cmd_action_tooltip", JsonString(sText + " do actions")); + NuiSetBind(oPC, nToken, "btn_cmd_guard_tooltip", JsonString(sText + " enter guard mode")); + NuiSetBind(oPC, nToken, "btn_cmd_hold_tooltip", JsonString(sText + " enter hold mode")); + NuiSetBind(oPC, nToken, "btn_cmd_attack_tooltip", JsonString(sText + " enter normal mode")); + object oTarget = GetLocalObject(oAssociate, AI_FOLLOW_TARGET); + string sTarget; + if(oTarget != OBJECT_INVALID) sTarget = GetName(oTarget); + else + { + if(ai_GetIsCharacter(oAssociate)) sTarget = "nobody"; + else sTarget = GetName(oPC); + } + NuiSetBind(oPC, nToken, "btn_follow_target_tooltip", JsonString(" " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]")); + // Row 7 + NuiSetBind(oPC, nToken, "chbx_cmd_ai_script_check", JsonBool (bCmdAIScript)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_ai_script_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_ai_script_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_event", JsonBool (TRUE)); + sText = " Using normal tactics"; + if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != "") + { + string sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + if(sScript == "ai_a_ambusher") sText = " Ambusher: Attacks from a hidden position"; + else if(sScript == "ai_a_flanker") sText = " Flanker: Attacks enemies engaged with allies"; + else if(sScript == "ai_a_peaceful") sText = " Peaceful: Avoids attacking any enemies if possible"; + else if(sScript == "ai_a_defensive") sText = " Defensive: Attacks then uses Expertise/Parry"; + else if(sScript == "ai_a_ranged") sText = " Ranged: Attacks from range as much as possible"; + else if(sScript == "ai_a_cntrspell") sText = " Counter Spell: Tries to counter enemy spells"; + } + else + { + if(GetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, oAssociate)) sText = "Using ambush tactics"; + else if(GetCombatCondition(X0_COMBAT_FLAG_COWARDLY, oAssociate)) sText = "Using coward tactics"; + else if(GetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, oAssociate)) sText = "Using defensive tactics"; + else if(GetCombatCondition(X0_COMBAT_FLAG_RANGED, oAssociate)) sText = "Using ranged tactics"; + } + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_tooltip", JsonString(sText)); + if(GetSkillRank(SKILL_SET_TRAP, oAssociate, TRUE) > 0) + { + NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_check", JsonBool (bCmdPlacetrap)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_place_trap_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_tooltip", JsonString ( + " Place a trap at the location selected")); + } + // Row 8 + NuiSetBind(oPC, nToken, "btn_quick_widget_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_quick_widget_tooltip", JsonString( + " Add/Remove abilities and spells from creatures widget")); + NuiSetBind(oPC, nToken, "chbx_quick_widget_check", JsonBool (bSpellWidget)); + NuiSetBindWatch (oPC, nToken, "chbx_quick_widget_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_quick_widget_event", JsonBool(TRUE)); + if(bMemorize == 2) // Memorizes their spells. + { + NuiSetBind(oPC, nToken, "btn_spell_memorize_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_spell_memorize_tooltip", JsonString( + " Change memorized spell list.")); + } + if(bSpellbook) // Change known spells. + { + NuiSetBind(oPC, nToken, "btn_spell_known_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_spell_known_tooltip", JsonString( + " Change known spell list.")); + } + // Row 9 + NuiSetBind(oPC, nToken, "chbx_buff_short_check", JsonBool (bBuffShort)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_short_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_short_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_short_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_buff_short_tooltip", JsonString ( + " Buff the party with short duration spells")); + NuiSetBind(oPC, nToken, "chbx_buff_long_check", JsonBool (bBuffLong)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_long_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_long_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_long_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_long_tooltip", JsonString ( + " Buff the party with long duration spells")); + // Row 10 + NuiSetBind(oPC, nToken, "chbx_buff_all_check", JsonBool (bBuffAll)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_all_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_all_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_all_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_all_tooltip", JsonString ( + " Buff the party with all our defensive spells")); + if(!bIsPC && ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) == "") + { + NuiSetBind(oPC, nToken, "chbx_buff_rest_check", JsonBool (bBuffRest)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_rest_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_rest_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_rest_event", JsonBool (TRUE)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST)) sText = " [On] Turn buffing after resting off"; + else sText = " [Off] Turn buffing after resting on"; + NuiSetBind (oPC, nToken, "btn_buff_rest_tooltip", JsonString (sText)); + } + // Row 11 + NuiSetBind(oPC, nToken, "chbx_jump_to_check", JsonBool(bJumpTo)); + NuiSetBindWatch (oPC, nToken, "chbx_jump_to_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_jump_to_event", JsonBool(TRUE)); + sText = GetName(oPC); + if(oPC == oAssociate) sName = "everyone"; + else sName = GetName(oAssociate); + NuiSetBind(oPC, nToken, "btn_jump_to_label", JsonString("Jump to " + sText)); + NuiSetBind(oPC, nToken, "btn_jump_to_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_jump_to_tooltip", JsonString ( + " Jump " + sName + " to " + sText)); + + NuiSetBind(oPC, nToken, "chbx_ghost_mode_check", JsonBool (bGhostMode)); + NuiSetBindWatch (oPC, nToken, "chbx_ghost_mode_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ghost_mode_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ghost_mode_event", JsonBool (TRUE)); + sText = "On"; + if(ai_GetAIMode(oAssociate, AI_MODE_GHOST)) sText = "Off"; + NuiSetBind(oPC, nToken, "btn_ghost_mode_tooltip", JsonString ( + " Turn " + sText + " clipping through creatures for " + GetName(oAssociate))); + // Row 12 + NuiSetBind(oPC, nToken, "chbx_camera_check", JsonBool (bCamera)); + NuiSetBindWatch (oPC, nToken, "chbx_camera_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_camera_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString ( + " Toggle camera view for " + sName)); + NuiSetBind(oPC, nToken, "chbx_inventory_check", JsonBool (bInventory)); + NuiSetBindWatch (oPC, nToken, "chbx_inventory_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_inventory_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString ( + " Open " + sName + " inventory")); + // Row 13 & 14 + if(bFamiliar) + { + NuiSetBind(oPC, nToken, "chbx_familiar_check", JsonBool(bBtnFamiliar)); + NuiSetBindWatch (oPC, nToken, "chbx_familiar_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_familiar_event", JsonBool(TRUE)); + int nFamiliar = GetFamiliarCreatureType(oAssociate); + NuiSetBind(oPC, nToken, "cmb_familiar_selected", JsonInt(nFamiliar)); + string sFamiliarName = GetFamiliarName(oAssociate); + NuiSetBind(oPC, nToken, "txt_familiar_name", JsonString(sFamiliarName)); + if(!bIsPC) + { + NuiSetBind(oPC, nToken, "lbl_familiar_type_label", JsonString("Change familiar type")); + NuiSetBind(oPC, nToken, "lbl_familiar_name_label", JsonString("Change familiar name")); + NuiSetBind(oPC, nToken, "cmb_familiar_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "cmb_familiar_selected", TRUE); + NuiSetBind(oPC, nToken, "txt_familiar_name_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "txt_familiar_name", TRUE); + NuiSetBind(oPC, nToken, "btn_familiar_name_label", JsonString("Save")); + } + else + { + NuiSetBind(oPC, nToken, "lbl_familiar_type_label", JsonString("Familiar type")); + NuiSetBind(oPC, nToken, "lbl_familiar_name_label", JsonString("Familiar name")); + } + } + // Row 15 & 16 + if(bCompanion) + { + NuiSetBind(oPC, nToken, "chbx_companion_check", JsonBool(bBtnCompanion)); + NuiSetBindWatch (oPC, nToken, "chbx_companion_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_companion_event", JsonBool(TRUE)); + int nCompanion = GetAnimalCompanionCreatureType(oAssociate); + NuiSetBind(oPC, nToken, "cmb_companion_selected", JsonInt(nCompanion)); + string sCompanionName = GetAnimalCompanionName(oAssociate); + NuiSetBind(oPC, nToken, "txt_companion_name", JsonString(sCompanionName)); + if(!bIsPC) + { + NuiSetBind(oPC, nToken, "lbl_companion_type_label", JsonString("Change Companion type")); + NuiSetBind(oPC, nToken, "lbl_companion_name_label", JsonString("Change Companion name")); + NuiSetBind(oPC, nToken, "cmb_companion_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "cmb_companion_selected", TRUE); + NuiSetBind(oPC, nToken, "txt_companion_name_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "txt_companion_name", TRUE); + NuiSetBind(oPC, nToken, "btn_companion_name_label", JsonString("Save")); + } + else + { + NuiSetBind(oPC, nToken, "lbl_companion_type_label", JsonString("Companion type")); + NuiSetBind(oPC, nToken, "lbl_companion_name_label", JsonString("Companion name")); + } + } + if(bIsPC) + { + // Row 17+ + int nIndex, bWidget; + string sButton, sText; + json jPlugin = JsonArrayGet(jPCPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_event", JsonBool(TRUE)); + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bWidget < 3) + { + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_check", JsonBool(bWidget)); + NuiSetBindWatch (oPC, nToken, "chbx_plugin_" + sButton + "_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_event", JsonBool(TRUE)); + } + sText = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_tooltip", JsonString(sText)); + jPlugin = JsonArrayGet(jPCPlugins, ++nIndex); + } + NuiSetBind(oPC, nToken, "chbx_plugin_tooltip", JsonString(" Adds the plugin to your widget.")); + } + // Row 18 + sText = ai_GetRandomTip(); + NuiSetBind(oPC, nToken, "lbl_info_1_label", JsonString(sText)); +} +void ai_CreateAssociateAINUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int bRight, bLeft; + float fHeight = 45.0; + // ************************************************************************* Width / Height + int bIsPC = ai_GetIsCharacter(oAssociate); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jRow = JsonArray(); + json jCol = JsonArray(); + // Row 1 ******************************************************************* 500 / 73 + // If all the AI buttons are blocked then don't load the menu. + if(bIsPC) + { + bRight = GetLocalInt(GetModule(), sDMWidgetAccessVarname) != 7340028; + if(!AI_SERVER || bRight) + { + // If all the Command buttons are blocked then don't load the menu. + if(bRight) + { + jRow = CreateButton(jRow, "Command Menu", "btn_command_menu", 200.0, 20.0, -1.0, "btn_command_menu_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_2", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(!AI_SERVER) + { + CreateButton(jRow, "Main Menu", "btn_main_menu", 200.0, 20.0, -1.0, "btn_main_menu_tooltip"); + CreateLabel(jRow, "", "blank_label_2", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + } + // Row 2 ******************************************************************* 500 / 73 + bRight = !ai_GetDMAIAccessButton(BTN_AI_LOOT); + if(bRight || !bIsPC) + { + jRow = JsonArray(); + if(!bIsPC) + { + jRow = CreateButton(jRow, "Command Menu", "btn_command_menu", 200.0, 20.0, -1.0, "btn_command_menu_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_2", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bRight) + { + jRow = CreateButton(jRow, "Loot Filter", "btn_loot_filter", 200.0, 20.0); + jRow = CreateLabel(jRow, "", "blank_label_2", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 3 ******************************************************************* 500 / 101 + bRight = !ai_GetDMAIAccessButton(BTN_AI_FOR_PC); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_REDUCE_SPEECH); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Player AI On/Off", "btn_ai", 200.0, 20.0, -1.0, "btn_ai_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ai", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Reduce Speech", "btn_quiet", 200.0, 20.0, -1.0, "btn_quiet_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_quiet", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 4 ******************************************************************* 500 / 129 + bRight = !ai_GetDMAIAccessButton(BTN_AI_USE_RANGED); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_STOP_WEAPON_EQUIP); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Ranged Combat", "btn_ranged", 200.0, 20.0, -1.0, "btn_ranged_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ranged", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Equip Best Weapons", "btn_equip_weapon", 200.0, 20.0, -1.0, "btn_equip_weapon_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_equip_weapon", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 5 ******************************************************************* 500 / 157 + bRight = !ai_GetDMAIAccessButton(BTN_AI_USE_SEARCH); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_USE_STEALTH); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Search Mode", "btn_search", 200.0, 20.0, -1.0, "btn_search_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_search", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Stealth Mode", "btn_stealth", 200.0, 20.0, -1.0, "btn_stealth_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_stealth", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 6 ******************************************************************* 500 / 185 + bRight = !ai_GetDMAIAccessButton(BTN_AI_OPEN_DOORS); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_REMOVE_TRAPS); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Open Door Mode", "btn_open_door", 200.0, 20.0, -1.0, "btn_open_door_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_open_door", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Disarm Traps Mode", "btn_traps", 200.0, 20.0, -1.0, "btn_traps_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_traps", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 7 ******************************************************************* 500 / 213 + bRight = !ai_GetDMAIAccessButton(BTN_AI_PICK_LOCKS); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_BASH_LOCKS); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Pick Locks Mode", "btn_pick_locks", 200.0, 20.0, -1.0, "btn_pick_locks_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_pick_locks", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Bash Mode", "btn_bash_locks", 200.0, 20.0, -1.0, "btn_bash_locks_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_bash_locks", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 8 ******************************************************************* 500 / 241 + bRight = !ai_GetDMAIAccessButton(BTN_AI_MAGIC_LEVEL); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_NO_SPONTANEOUS); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Magic usage level", "btn_magic_level", 200.0, 20.0f, -1.0, "btn_magic_level_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic_level", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Cleric Spontaneous Casting", "btn_spontaneous", 200.0, 20.0, -1.0, "btn_spontaneous_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_spontaneous", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 9 ******************************************************************* 500 / 269 + bRight = !ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_USE); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_ITEM_USE); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Use Magic", "btn_magic", 200.0, 20.0, -1.0, "btn_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Use Magic Items", "btn_magic_items", 200.0, 20.0, -1.0, "btn_magic_items_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic_items", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 10 ****************************************************************** 500 / 297 + bRight = !ai_GetDMAIAccessButton(BTN_AI_DEF_MAGIC_USE); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_OFF_MAGIC_USE); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Use Defensive Magic Only", "btn_def_magic", 200.0, 20.0, -1.0, "btn_def_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_def_magic", 25.0, 20.0f); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Use Offensive Magic Only", "btn_off_magic", 200.0, 20.0, -1.0, "btn_off_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_off_magic", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 11 ****************************************************************** 500 / 325 + bRight = !ai_GetDMAIAccessButton(BTN_AI_HEAL_OUT); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_HEAL_IN); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Heal % Out of Combat", "btn_heal_out", 200.0, 20.0, -1.0, "btn_heal_out_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heal_out", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Heal % in Combat", "btn_heal_in", 200.0, 20.0, -1.0, "btn_heal_in_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heal_in", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 12 ****************************************************************** 500 / 353 + bRight = !ai_GetDMAIAccessButton(BTN_AI_STOP_SELF_HEALING); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_STOP_PARTY_HEALING); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Self Healing", "btn_heals_onoff", 200.0, 20.0, -1.0, "btn_heals_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heals_onoff", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Party Healing", "btn_healp_onoff", 200.0, 20.0, -1.0, "btn_healp_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_healp_onoff", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 13 ****************************************************************** 500 / 391 + bRight = !ai_GetDMAIAccessButton(BTN_AI_STOP_CURE_SPELLS); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_LOOT); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Cast Cure Spells", "btn_cure_onoff", 200.0, 20.0, -1.0, "btn_cure_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cure_onoff", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + if(sAssociateType != "summons" && sAssociateType != "dominated") + { + jRow = CreateButton(jRow, "Auto Looting", "btn_loot", 200.0, 20.0, -1.0, "btn_loot_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_loot", 25.0, 20.0); + } + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 14 ****************************************************************** 500 / --- + bRight = !ai_GetDMAIAccessButton(BTN_AI_IGNORE_ASSOCIATES); + bLeft = !ai_GetDMAIAccessButton(BTN_AI_IGNORE_TRAPS); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + jRow = CreateButton(jRow, "Ignore Associates", "btn_ignore_assoc", 200.0, 20.0, -1.0, "btn_ignore_assoc_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ignore_assoc", 25.0, 20.0); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + jRow = CreateButton(jRow, "Ignore floor Traps", "btn_ignore_traps", 200.0, 20.0, -1.0, "btn_ignore_traps_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ignore_traps", 25.0, 20.0); + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 15 ****************************************************************** 500 / --- + bRight = !ai_GetDMAIAccessButton(BTN_AI_PERC_RANGE); + bLeft = FALSE; //!ai_GetDMAIAccessButton(BTN_AI_PERC_RANGE); + if(bRight || bLeft) + { + jRow = JsonArray(); + if(bRight) + { + if(GetAssociateType(oAssociate) == ASSOCIATE_TYPE_HENCHMAN) + { + jRow = CreateButton(jRow, "Perception Range", "btn_perc_range", 200.0, 20.0, -1.0, "btn_perc_range_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_perc_range", 25.0, 20.0); + } + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + if(bLeft) + { + } + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 16 ****************************************************************** 500 / --- + bRight = !ai_GetDMWAccessButton(BTN_CMD_AI_SCRIPT); + if(bRight) + { + jRow = JsonArray(); + jRow = CreateButton(jRow, "Set Current AI:", "btn_ai_script", 175.0f, 20.0f, -1.0, "btn_ai_script_tooltip"); + jRow = CreateTextEditBox(jRow, "sPlaceHolder", "txt_ai_script", 16, FALSE, 145.0f, 20.0f, "txt_ai_script_tooltip"); + jRow = CreateCombo(jRow, ai_CreateAIScriptJson(oPC), "cmb_ai_script", 146.0, 20.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + // Row 17 ****************************************************************** 500 / --- + jRow = JsonArray(); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "", "lbl_info", 475.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sText, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_NUI, sName + " AI Menu", + fX, fY, 500.0, fHeight + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Get which buttons are activated. + int bAI = ai_GetAIButton(oPC, BTN_AI_FOR_PC, oAssociate, sAssociateType); + int bReduceSpeech = ai_GetAIButton(oPC, BTN_AI_REDUCE_SPEECH, oAssociate, sAssociateType); + int bRanged = ai_GetAIButton(oPC, BTN_AI_USE_RANGED, oAssociate, sAssociateType); + int bEquipWeapons = ai_GetAIButton(oPC, BTN_AI_STOP_WEAPON_EQUIP, oAssociate, sAssociateType); + int bSearch = ai_GetAIButton(oPC, BTN_AI_USE_SEARCH, oAssociate, sAssociateType); + int bStealth = ai_GetAIButton(oPC, BTN_AI_USE_STEALTH, oAssociate, sAssociateType); + int bOpenDoors = ai_GetAIButton(oPC, BTN_AI_OPEN_DOORS, oAssociate, sAssociateType); + int bTraps = ai_GetAIButton(oPC, BTN_AI_REMOVE_TRAPS, oAssociate, sAssociateType); + int bPickLocks = ai_GetAIButton(oPC, BTN_AI_PICK_LOCKS, oAssociate, sAssociateType); + int bBashLocks = ai_GetAIButton(oPC, BTN_AI_BASH_LOCKS, oAssociate, sAssociateType); + int bMagicLevel = ai_GetAIButton(oPC, BTN_AI_MAGIC_LEVEL, oAssociate, sAssociateType); + int bSpontaneous = ai_GetAIButton(oPC, BTN_AI_NO_SPONTANEOUS, oAssociate, sAssociateType); + int bNoMagic = ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_USE, oAssociate, sAssociateType); + int bNoMagicItems = ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_ITEM_USE, oAssociate, sAssociateType); + int bDefMagic = ai_GetAIButton(oPC, BTN_AI_DEF_MAGIC_USE, oAssociate, sAssociateType); + int bOffMagic = ai_GetAIButton(oPC, BTN_AI_OFF_MAGIC_USE, oAssociate, sAssociateType); + int bHealOut = ai_GetAIButton(oPC, BTN_AI_HEAL_OUT, oAssociate, sAssociateType); + int bHealIn = ai_GetAIButton(oPC, BTN_AI_HEAL_IN, oAssociate, sAssociateType); + int bSelfHealOnOff = ai_GetAIButton(oPC, BTN_AI_STOP_SELF_HEALING, oAssociate, sAssociateType); + int bPartyHealOnOff = ai_GetAIButton(oPC, BTN_AI_STOP_PARTY_HEALING, oAssociate, sAssociateType); + int bCureOnOff = ai_GetAIButton(oPC, BTN_AI_STOP_CURE_SPELLS, oAssociate, sAssociateType); + int bIgnoreAssociates = ai_GetAIButton(oPC, BTN_AI_IGNORE_ASSOCIATES, oAssociate, sAssociateType); + int bIgnoreTraps = ai_GetAIButton(oPC, BTN_AI_IGNORE_TRAPS, oAssociate, sAssociateType); + int bLoot = ai_GetAIButton(oPC, BTN_AI_LOOT, oAssociate, sAssociateType); + int bPercRange = ai_GetAIButton(oPC, BTN_AI_PERC_RANGE, oAssociate, sAssociateType); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArray(); + jData = JsonArrayInsert(jData, JsonString(ObjectToString(oAssociate))); + NuiSetUserData(oPC, nToken, jData); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 + // If all the AI buttons are blocked then don't load the menu. + if(bIsPC) + { + bRight = GetLocalInt(GetModule(), sDMWidgetAccessVarname) != 7340028; + if(!AI_SERVER || bRight) + { + // If all the Command buttons are blocked then don't load the menu. + if(bRight) + { + NuiSetBind(oPC, nToken, "btn_command_menu_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_command_menu_tooltip", JsonString(" " + sName + " Command options")); + } + if(!AI_SERVER) + { + NuiSetBind(oPC, nToken, "btn_main_menu_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_main_menu_tooltip", JsonString(" Module Options")); + } + fHeight += 28.0; + } + } + // Row 2 + if(!bIsPC) + { + NuiSetBind(oPC, nToken, "btn_command_menu_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_command_menu_tooltip", JsonString(" " + sName + " Command options")); + } + NuiSetBind(oPC, nToken, "btn_loot_filter_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_filter", JsonInt(TRUE)); + // Row 3 + // Only activate ai on/off if this is for the pc. + if(bIsPC && ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) == "") + { + NuiSetBind(oPC, nToken, "chbx_ai_check", JsonBool(bAI)); + NuiSetBindWatch (oPC, nToken, "chbx_ai_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ai_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_event", JsonBool(TRUE)); + if(GetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT) == "xx_pc_1_hb") sText = " AI On"; + else sText = " AI Off"; + NuiSetBind(oPC, nToken, "btn_ai_tooltip", JsonString(sText)); + } + NuiSetBind(oPC, nToken, "chbx_quiet_check", JsonBool(bReduceSpeech)); + NuiSetBindWatch (oPC, nToken, "chbx_quiet_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_quiet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_quiet_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK)) sText = " Reduced Speech On"; + else sText = " Reduces Speech Off"; + NuiSetBind (oPC, nToken, "btn_quiet_tooltip", JsonString(sText)); + // Row 4 + NuiSetBind(oPC, nToken, "chbx_ranged_check", JsonBool(bRanged)); + NuiSetBindWatch(oPC, nToken, "chbx_ranged_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ranged_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ranged_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED)) sText = " Ranged Off"; + else sText = " Ranged On"; + NuiSetBind (oPC, nToken, "btn_ranged_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "chbx_equip_weapon_check", JsonBool(bEquipWeapons)); + NuiSetBindWatch(oPC, nToken, "chbx_equip_weapon_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_equip_weapon_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_equip_weapon_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF)) sText = " Equiping Best Weapons Off"; + else sText = " Equiping Best Weapons On"; + NuiSetBind (oPC, nToken, "btn_equip_weapon_tooltip", JsonString(sText)); + // Row 5 + if(GetRacialType(oAssociate) != RACIAL_TYPE_ELF) + { + NuiSetBind(oPC, nToken, "chbx_search_check", JsonBool(bSearch)); + NuiSetBindWatch (oPC, nToken, "chbx_search_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_search_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_search_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH)) sText = " Search mode On"; + else sText = " Search mode Off"; + NuiSetBind (oPC, nToken, "btn_search_tooltip", JsonString(sText)); + } + NuiSetBind(oPC, nToken, "chbx_stealth_check", JsonBool(bStealth)); + NuiSetBindWatch(oPC, nToken, "chbx_stealth_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_stealth_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_stealth_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH)) sText = " Stealth mode On"; + else sText = " Stealth mode Off"; + NuiSetBind (oPC, nToken, "btn_stealth_tooltip", JsonString(sText)); + // Row 6 + string sRange = FloatToString(GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "chbx_open_door_check", JsonBool(bOpenDoors)); + NuiSetBindWatch (oPC, nToken, "chbx_open_door_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_open_door_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_open_door_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS)) sText = " Open Doors On [" + sRange + " meters]"; + else sText = " Open Doors Off [" + sRange + " meters]"; + NuiSetBind (oPC, nToken, "btn_open_door_tooltip", JsonString(sText)); + sRange = FloatToString(GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "chbx_traps_check", JsonBool(bTraps)); + NuiSetBindWatch (oPC, nToken, "chbx_traps_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_traps_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_traps_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS)) sText = " Disable Traps On [" + sRange + " meters]"; + else sText = " Disable Traps Off [" + sRange + " meters]"; + NuiSetBind (oPC, nToken, "btn_traps_tooltip", JsonString(sText)); + // Row 7 + sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "chbx_pick_locks_check", JsonBool(bPickLocks)); + NuiSetBindWatch(oPC, nToken, "chbx_pick_locks_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_pick_locks_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_pick_locks_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS)) sText = " Pick locks On [" + sRange + " meters]"; + else sText = " Pick Locks Off [" + sRange + " meters]"; + NuiSetBind (oPC, nToken, "btn_pick_locks_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "chbx_bash_locks_check", JsonBool(bBashLocks)); + NuiSetBindWatch(oPC, nToken, "chbx_bash_locks_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_bash_locks_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_bash_locks_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) sText = " Bash On [" + sRange + " meters]"; + else sText = " Bash Off [" + sRange + " meters]"; + NuiSetBind (oPC, nToken, "btn_bash_locks_tooltip", JsonString(sText)); + // Row 8 + string sMagic = IntToString(GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT)); + NuiSetBind(oPC, nToken, "chbx_magic_level_check", JsonBool(bMagicLevel)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_level_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_level_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_level_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_magic_level_tooltip", JsonString(" Magic level [" + sMagic + "]")); + sText = " Spontaneous casting On"; + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE)) sText = " Spontaneous casting Off"; + NuiSetBind(oPC, nToken, "chbx_spontaneous_check", JsonBool(bSpontaneous)); + NuiSetBindWatch (oPC, nToken, "chbx_spontaneous_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_spontaneous_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spontaneous_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spontaneous_tooltip", JsonString(sText)); + // Row 9 + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC)) sText = " Magic Off"; + else sText = " Magic On"; + NuiSetBind(oPC, nToken, "chbx_magic_check", JsonBool(bNoMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_tooltip", JsonString(sText)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS)) sText = " Magic Items Off"; + else sText = " Magic Items On"; + NuiSetBind(oPC, nToken, "chbx_magic_items_check", JsonBool(bNoMagicItems)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_items_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_items_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_items_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_items_tooltip", JsonString(sText)); + // Row 10 + if(ai_GetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING)) sText = " Defensive Magic On"; + else sText = " Defensive Magic Off"; + NuiSetBind(oPC, nToken, "chbx_def_magic_check", JsonBool (bDefMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_def_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_def_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_def_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_def_magic_tooltip", JsonString(sText)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING)) sText = " Offensive Magic On"; + else sText = " Offensive Magic Off"; + NuiSetBind(oPC, nToken, "chbx_off_magic_check", JsonBool(bOffMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_off_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_off_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_off_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_off_magic_tooltip", JsonString(sText)); + // Row 11 + int nHeal = GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT); + NuiSetBind(oPC, nToken, "chbx_heal_out_check", JsonBool(bHealOut)); + NuiSetBindWatch (oPC, nToken, "chbx_heal_out_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heal_out_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_out_event", JsonBool(TRUE)); + sText = " Will heal at or below [" + IntToString(nHeal) + "%] health out of combat"; + NuiSetBind(oPC, nToken, "btn_heal_out_tooltip", JsonString(sText)); + nHeal = GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT); + NuiSetBind(oPC, nToken, "chbx_heal_in_check", JsonBool(bHealIn)); + NuiSetBindWatch (oPC, nToken, "chbx_heal_in_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heal_in_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_in_event", JsonBool (TRUE)); + sText = " Will heal at or below [" + IntToString(nHeal) + "%] health in combat"; + NuiSetBind(oPC, nToken, "btn_heal_in_tooltip", JsonString(sText)); + // Row 12 + NuiSetBind(oPC, nToken, "chbx_heals_onoff_check", JsonBool(bSelfHealOnOff)); + NuiSetBindWatch (oPC, nToken, "chbx_heals_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heals_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heals_onoff_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF)) sText = " Self healing Off"; + else sText = " Self healing On"; + NuiSetBind(oPC, nToken, "btn_heals_onoff_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "chbx_healp_onoff_check", JsonBool(bPartyHealOnOff)); + NuiSetBind(oPC, nToken, "chbx_healp_onoff_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_healp_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "btn_healp_onoff_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF)) sText = " Party healing Off"; + else sText = " Party healing On"; + NuiSetBind(oPC, nToken, "btn_healp_onoff_tooltip", JsonString(sText)); + // Row 13 + NuiSetBind(oPC, nToken, "btn_cure_onoff_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "chbx_cure_onoff_check", JsonBool(bCureOnOff)); + NuiSetBind(oPC, nToken, "chbx_cure_onoff_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_cure_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cure_onoff_event", JsonBool(TRUE)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF)) sText = " Cast Cure Spells Off"; + else sText = " Cast Cure Spells On"; + NuiSetBind(oPC, nToken, "btn_cure_onoff_tooltip", JsonString(sText)); + if(sAssociateType != "summons" && sAssociateType != "dominated") + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE), 0, 0); + if(ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS)) sText = " Looting On [" + sRange + " meters]"; + else sText = " Looting Off [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "chbx_loot_check", JsonBool(bLoot)); + NuiSetBindWatch (oPC, nToken, "chbx_loot_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_tooltip", JsonString(sText)); + } + // Row 14 + NuiSetBind(oPC, nToken, "chbx_ignore_assoc_check", JsonBool(bIgnoreAssociates)); + NuiSetBindWatch(oPC, nToken, "chbx_ignore_assoc_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ignore_assoc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ignore_assoc_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES)) sText = " Ignore Enemy Associates On"; + else sText = " Ignore Enemy Associates Off"; + NuiSetBind (oPC, nToken, "btn_ignore_assoc_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "chbx_ignore_traps_check", JsonBool(bIgnoreTraps)); + NuiSetBindWatch(oPC, nToken, "chbx_ignore_traps_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ignore_traps_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ignore_traps_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS)) sText = " Ignore Floor Traps On"; + else sText = " Ignore Floor Traps Off"; + NuiSetBind (oPC, nToken, "btn_ignore_traps_tooltip", JsonString(sText)); + // Row 15 + if(!bIsPC) + { + int nRange = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU"); + if(nRange < 8 || nRange > 11) + { + nRange = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION); + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU", nRange); + } + if(nRange == 8) sText = " Perception Range Short [10 meters Sight / 10 meters Listen]"; + else if(nRange == 9) sText = " Perception Range Medium [20 meters Sight / 20 meters Listen]"; + else if(nRange == 10) sText = " Perception Range Long [35 meters Sight / 20 meters Listen]"; + else sText = " Perception Range Default [20 meters Sight / 20 meters Listen]"; + NuiSetBind(oPC, nToken, "chbx_perc_range_check", JsonBool(bPercRange)); + NuiSetBindWatch (oPC, nToken, "chbx_perc_range_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_perc_range_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_perc_range_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_perc_range_tooltip", JsonString(sText)); + } + // Row 16 + string sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + if(sScript == "") sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + NuiSetBind(oPC, nToken, "btn_ai_script_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_script_tooltip", JsonString(" Sets " + GetName(oAssociate) + " to use the ai script in the text box.")); + NuiSetBind(oPC, nToken, "txt_ai_script_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_ai_script", JsonString(sScript)); + NuiSetBind(oPC, nToken, "txt_ai_script_tooltip", JsonString(" Associate AI scripts must start with ai_a_")); + NuiSetBind(oPC, nToken, "cmb_ai_script_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "cmb_ai_script_selected", TRUE); + // Row 17 + sText = ai_GetRandomTip(); + NuiSetBind (oPC, nToken, "lbl_info_label", JsonString(sText)); +} +void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int nToken, string sName) +{ + int bBool, bIsPC = ai_GetIsCharacter(oAssociate); + string sText, sRange, sHeal; + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set the buttons to show events. + NuiSetBind(oPC, nToken, "btn_open_main_image", JsonString(GetPortraitResRef(oAssociate) + "s")); + NuiSetBind(oPC, nToken, "btn_open_main_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_open_main_tooltip", JsonString(" " + sName + " widget menu")); + if(bIsPC) sText = " All associates"; + else sText = " " + GetName(oAssociate); + if(ai_GetWidgetButton(oPC, BTN_CMD_ACTION, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_action_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_action_tooltip", JsonString(sText + " do actions")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_GUARD, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_guard_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_guard_tooltip", JsonString(sText + " enter guard mode")); + bBool = ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER); + NuiSetBind(oPC, nToken, "btn_cmd_guard_encouraged", JsonBool(bBool)); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_HOLD, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_hold_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_hold_tooltip", JsonString(sText + " enter hold mode")); + bBool = ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND); + NuiSetBind(oPC, nToken, "btn_cmd_hold_encouraged", JsonBool(bBool)); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_ATTACK, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_attack_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_attack_tooltip", JsonString(sText + " enter normal mode")); + if(!bIsPC) + { + if(!ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER) && + !ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND) && + !ai_GetAIMode(oAssociate, AI_MODE_FOLLOW)) bBool = TRUE; + else bBool = FALSE; + if(!bIsPC) NuiSetBind(oPC, nToken, "btn_cmd_attack_encouraged", JsonBool(bBool)); + } + } + if(ai_GetWidgetButton(oPC, BTN_CMD_FOLLOW, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_follow_event", JsonBool(TRUE)); + float fRange = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + + StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate))); + string sRange = FloatToString(fRange, 0, 0); + if(bIsPC) + { + sText = " All associates"; + NuiSetBind(oPC, nToken, "btn_cmd_follow_tooltip", JsonString(sText + " enter follow mode")); + } + else + { + sText = " " + GetName(oAssociate); + NuiSetBind(oPC, nToken, "btn_cmd_follow_tooltip", JsonString(sText + " enter follow mode [" + sRange + " meters]")); + } + bBool = ai_GetAIMode(oAssociate, AI_MODE_FOLLOW); + if(!bIsPC) NuiSetBind(oPC, nToken, "btn_cmd_follow_encouraged", JsonBool(bBool)); + } + if(ai_GetAIButton(oPC, BTN_AI_FOLLOW_TARGET, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_follow_target_event", JsonBool(TRUE)); + object oTarget = GetLocalObject(oAssociate, AI_FOLLOW_TARGET); + string sTarget; + if(oTarget != OBJECT_INVALID) sTarget = GetName(oTarget); + else + { + if(ai_GetIsCharacter(oAssociate)) sTarget = "nobody"; + else sTarget = GetName(oPC); + } + float fRange = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + + StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate))); + string sRange = FloatToString(fRange, 0, 0); + NuiSetBind(oPC, nToken, "btn_follow_target_tooltip", JsonString(" " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_SEARCH, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_search_event", JsonBool(TRUE)); + if(ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_SEARCH)) sText = " leave "; + else sText = " enter "; + NuiSetBind(oPC, nToken, "btn_cmd_search_tooltip", JsonString(" Everyone" + sText + "search mode")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_STEALTH, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_stealth_event", JsonBool(TRUE)); + if(ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_STEALTH)) sText = " leave "; + else sText = " enter "; + NuiSetBind(oPC, nToken, "btn_cmd_stealth_tooltip", JsonString(" Everyone" + sText + "stealth mode")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_AI_SCRIPT, oAssociate, sAssociateType)) + { + sText = " Default tactics: Using the creatures base AI script"; + string sIcon = "ir_scommand"; + if(ResManGetAliasFor("0e_ch_1_hb", RESTYPE_NCS) != "") + { + string sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT); + if(sScript == "ai_a_ambusher") + { + sText = " Ambusher: Attacks from a hidden position"; + sIcon = "ir_rogue"; + } + else if(sScript == "ai_a_flanker") + { + sText = " Flanker: Attacks enemies engaged with allies"; + sIcon = "ir_invite"; + } + else if(sScript == "ai_a_peaceful") + { + sText = " Peaceful: Avoids attacking any enemies if possible"; + sIcon = "ir_ignore"; + } + else if(sScript == "ai_a_defensive") + { + sText = " Defensive: Attacks then uses Expertise/Parry"; + sIcon = "ir_knockdwn"; + } + else if(sScript == "ai_a_ranged") + { + sText = " Ranged: Attacks from range as much as possible"; + sIcon = "ir_ranger"; + } + else if(sScript == "ai_a_cntrspell") + { + sText = " Counter Spell: Tries to counter enemy spells"; + sIcon = "ir_dcaster"; + } + } + else + { + if(GetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, oAssociate)) sText = "Using ambush tactics"; + if(GetCombatCondition(X0_COMBAT_FLAG_COWARDLY, oAssociate)) sText = "Using coward tactics"; + if(GetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, oAssociate)) sText = "Using defensive tactics"; + if(GetCombatCondition(X0_COMBAT_FLAG_RANGED, oAssociate)) sText = "Using ranged tactics"; + } + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_image", JsonString(sIcon)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_tooltip", JsonString(sText)); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_PLACE_TRAP, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_tooltip", JsonString(" Place a trap at the location selected")); + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_SHORT, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_buff_short_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_short_tooltip", JsonString(" Buff the party with short duration spells")); + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_LONG, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_buff_long_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_long_tooltip", JsonString(" Buff the party with long duration spells")); + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_ALL, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_buff_all_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_all_tooltip", JsonString(" Buff the party with all our defensive spells")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_JUMP_TO, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_jump_to_event", JsonBool(TRUE)); + sText = GetName(oPC); + if(oPC == oAssociate) sName = "everyone"; + else sName = GetName(oAssociate); + NuiSetBind(oPC, nToken, "btn_jump_to_tooltip", JsonString(" Jump " + sName + " to " + sText)); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_GHOST_MODE, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_ghost_mode_event", JsonBool (TRUE)); + sText = "On"; + if(ai_GetAIMode(oAssociate, AI_MODE_GHOST)) sText = "Off"; + NuiSetBind(oPC, nToken, "btn_ghost_mode_tooltip", JsonString ( + " Turn " + sText + " clipping through creatures for " + GetName(oAssociate))); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_CAMERA, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString(" Toggle camera view for " + sName)); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_INVENTORY, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString(" Open " + sName + " inventory")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_FAMILIAR, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_familiar_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_familiar_tooltip", JsonString(" Summon " + sName + " familiar.")); + } + if(ai_GetWidgetButton(oPC, BTN_CMD_COMPANION, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_companion_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_companion_tooltip", JsonString(" Open " + sName + " Animal Companion.")); + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_REST, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_buff_rest_event", JsonBool(TRUE)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST)) sText = " Turn buffing after resting off"; + else sText = " Turn buffing after resting on."; + NuiSetBind(oPC, nToken, "btn_buff_rest_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_FOR_PC, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_ai_event", JsonBool(TRUE)); + if(GetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT) == "xx_pc_1_hb") sText = " AI [On] Turn off"; + else sText = " AI [Off] Turn on"; + NuiSetBind(oPC, nToken, "btn_ai_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_REDUCE_SPEECH, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_quiet_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK)) sText = " Reduced Speech On"; + else sText = " Reduced Speech Off"; + NuiSetBind(oPC, nToken, "btn_quiet_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_USE_RANGED, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_ranged_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED)) sText = " Ranged Off"; + else sText = " Ranged On"; + NuiSetBind(oPC, nToken, "btn_ranged_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_WEAPON_EQUIP, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_equip_weapon_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF)) sText = " Equiping Best Weapons Off"; + else sText = " Equiping Best Weapons On"; + NuiSetBind(oPC, nToken, "btn_equip_weapon_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_USE_SEARCH, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_search_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH)) sText = " Search On"; + else sText = " Search Off"; + NuiSetBind(oPC, nToken, "btn_search_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_USE_STEALTH, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_stealth_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH)) sText = " Stealth On"; + else sText = " Stealth Off"; + NuiSetBind(oPC, nToken, "btn_stealth_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_OPEN_DOORS, oAssociate, sAssociateType)) + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "btn_open_door_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS)) sText = " Open Doors On [" + sRange + " meters]"; + else sText = " Open Doors Off [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "btn_open_door_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_REMOVE_TRAPS, oAssociate, sAssociateType)) + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "btn_traps_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS)) sText = " Disable Traps On [" + sRange + " meters]"; + else sText = " Disable Traps Off [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "btn_traps_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_PICK_LOCKS, oAssociate, sAssociateType)) + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "btn_pick_locks_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS)) sText = " Pick locks On [" + sRange + " meters]"; + else sText = " Pick Locks Off [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "btn_pick_locks_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_BASH_LOCKS, oAssociate, sAssociateType)) + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE), 0, 0); + NuiSetBind(oPC, nToken, "btn_bash_locks_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) sText = " Bash On [" + sRange + " meters]"; + else sText = " Bash Off [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "btn_bash_locks_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_MAGIC_LEVEL, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_magic_level_event", JsonBool(TRUE)); + string sMagic = IntToString(GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT)); + NuiSetBind(oPC, nToken, "btn_magic_level_tooltip", JsonString(" Magic Level [" + sMagic + "]")); + } + if(ai_GetAIButton(oPC, BTN_AI_NO_SPONTANEOUS, oAssociate, sAssociateType)) + { + string sCasting = " Spontaneous casting On"; + if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE)) sCasting = " Spontaneous casting Off"; + NuiSetBind(oPC, nToken, "btn_spontaneous_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spontaneous_tooltip", JsonString(sCasting)); + } + if(ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_USE, oAssociate, sAssociateType)) + { + if(ai_GetAIMode(oAssociate, AI_MAGIC_NO_MAGIC)) sText = " Magic Off"; + else sText = " Magic On"; + NuiSetBind(oPC, nToken, "btn_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_ITEM_USE, oAssociate, sAssociateType)) + { + if(ai_GetAIMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS)) sText = " Magic Items Off"; + else sText = " Magic Items On"; + NuiSetBind(oPC, nToken, "btn_magic_items_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_items_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_DEF_MAGIC_USE, oAssociate, sAssociateType)) + { + if(ai_GetAIMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING)) sText = " Defensive Magic On"; + else sText = " Defensive Magic Off"; + NuiSetBind(oPC, nToken, "btn_def_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_def_magic_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_OFF_MAGIC_USE, oAssociate, sAssociateType)) + { + if(ai_GetAIMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING)) sText = " Offensive Magic On"; + else sText = " Offensive Magic Off"; + NuiSetBind(oPC, nToken, "btn_off_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_off_magic_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_HEAL_OUT, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_heal_out_event", JsonBool(TRUE)); + sHeal = IntToString(GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT)); + sText = " Will heal at or below [" + sHeal + "%] health out of combat"; + NuiSetBind(oPC, nToken, "btn_heal_out_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_HEAL_IN, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_heal_in_event", JsonBool(TRUE)); + sHeal = IntToString(GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT)); + sText = " Will heal at or below [" + sHeal + "%] health in combat"; + NuiSetBind(oPC, nToken, "btn_heal_in_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_SELF_HEALING, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_heals_onoff_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF)) sText = " Self healing Off"; + else sText = " Self healing On"; + NuiSetBind(oPC, nToken, "btn_heals_onoff_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_PARTY_HEALING, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_healp_onoff_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF)) sText = " Party healing Off"; + else sText = " Party healing On"; + NuiSetBind(oPC, nToken, "btn_healp_onoff_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_CURE_SPELLS, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_cure_onoff_event", JsonBool(TRUE)); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF)) sText = " Cast Cure Spells Off"; + else sText = " Cast Cure Spells On"; + NuiSetBind(oPC, nToken, "btn_cure_onoff_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_LOOT, oAssociate, sAssociateType)) + { + sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE), 0, 0); + string sLoot = " Looting Off [" + sRange + " meters]"; + if(ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS)) sLoot = " Looting On [" + sRange + " meters]"; + NuiSetBind(oPC, nToken, "btn_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_tooltip", JsonString(sLoot)); + } + if(ai_GetAIButton(oPC, BTN_AI_IGNORE_ASSOCIATES, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_ignore_assoc_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES)) sText = " Ignore Enemy Associates On"; + else sText = " Ignore Enemy Associates Off"; + NuiSetBind(oPC, nToken, "btn_ignore_assoc_tooltip", JsonString(sText)); + } + if(ai_GetAIButton(oPC, BTN_AI_IGNORE_TRAPS, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_ignore_traps_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS)) sText = " Ignore Floor Traps On"; + else sText = " Ignore Floor Traps Off"; + NuiSetBind(oPC, nToken, "btn_ignore_traps_tooltip", JsonString(sText)); + } + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + if(ai_GetAIButton(oPC, BTN_AI_PERC_RANGE, oAssociate, sAssociateType)) + { + int nRange = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION); + if(nRange < 8 || nRange > 11) + { + nRange = 11; + SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, 11); + jAIData = JsonArraySet(jAIData, 7, JsonInt(11)); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + if(nRange == 8) sText = " Perception Range Short [10 meters Sight / 10 meters Listen]"; + if(nRange == 9) sText = " Perception Range Medium [20 meters Sight / 20 meters Listen]"; + if(nRange == 10) sText = " Perception Range Long [35 meters Sight / 20 meters Listen]"; + else sText = " Perception Range Default [20 meters Sight / 20 meters Listen]"; + NuiSetBind(oPC, nToken, "btn_perc_range_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_perc_range_tooltip", JsonString(sText)); + } + if(bIsPC) + { + int nIndex, bWidget; + string sButton, sName, sText, sScript; + json jPCPlugins = ai_UpdatePluginsForPC(oPC); + json jPlugin = JsonArrayGet(jPCPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bWidget) + { + sButton = IntToString(nIndex); + sScript = JsonGetString(JsonArrayGet(jPlugin, 0)); + if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "") + { + sText = " " + sScript + " not found by ResMan!"; + } + else sName = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_exe_plugin_" + sButton + "_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_exe_plugin_" + sButton + "_tooltip", JsonString(sName)); + } + jPlugin = JsonArrayGet(jPCPlugins, ++nIndex); + } + } + if(ai_GetWidgetButton(oPC, BTN_CMD_SPELL_WIDGET, oAssociate, sAssociateType)) + { + NuiSetBind(oPC, nToken, "btn_update_widget_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_update_widget_tooltip", JsonString(" Updates Quick Use Widget")); + json jSpell, jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + object oItem; + if(JsonGetType(jWidget) != JSON_TYPE_NULL) + { + int nLevel, nSpell, nIndex, nClass, nMetaMagic, nDomain, nSubSpell, nFeat; + string sSpellIcon, sMetaMagicText, sSubSpell, sClass, sIndex; + while(nIndex < 10) + { + jSpell = JsonArrayGet(jWidget, nIndex); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + sIndex = IntToString(nIndex); + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + if(nClass == -1) // This is an Item. + { + string sBaseName; + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + int nBaseItemType = JsonGetInt(JsonArrayGet(jSpell, 3)); + int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4)); + if(nSpell == SPELL_HEALINGKIT) + { + sName = "Healer's Kit +" + IntToString(nIprpSubType); + sSpellIcon = "isk_heal"; + sBaseName = "Healer's Kit"; + } + else if(nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL) + { + sSpellIcon = Get2DAString("iprp_spells", "Icon", nIprpSubType); + sBaseName = "Scroll"; + } + else + { + if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) sBaseName = "Potion"; + else if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == FEAT_CRAFT_WAND) sBaseName = "Wand"; + else sBaseName = ai_StripColorCodes(GetName(GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + int nUses = ai_GetItemUses(oItem, nIprpSubType); + if(nUses) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(nUses == 999) sText = "Unlimited"; + else sText = IntToString(nUses); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")")); + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + else + { + nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nFeat) // This is a feat. + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + sSpellIcon = ""; + if(nSpell) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + if(sSpellIcon == "" || sSpellIcon == "IR_USE") + { + sName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + sSpellIcon = Get2DAString("feat", "ICON", nFeat); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + if(GetHasFeat(nFeat, oAssociate)) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName)); + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + else // This is a spell. + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nLevel = JsonGetInt(JsonArrayGet(jSpell, 2)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + if(GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain)) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + } + } + else break; + ++nIndex; + } + while(nIndex < 20) + { + jSpell = JsonArrayGet(jWidget, nIndex); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + sIndex = IntToString(nIndex); + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nClass == -1) // This is an Item. + { + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + if(oItem != OBJECT_INVALID) + { + string sBaseName; + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + int nBaseItemType = JsonGetInt(JsonArrayGet(jSpell, 3)); + int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4)); + if(nSpell == SPELL_HEALINGKIT) + { + sName = "Healer's Kit +" + IntToString(nIprpSubType); + sSpellIcon = "isk_heal"; + sBaseName = "Healer's Kit"; + } + else if(nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL) + { + sSpellIcon = Get2DAString("iprp_spells", "Icon", nIprpSubType); + sBaseName = "Scroll"; + } + else + { + if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) sBaseName = "Potion"; + else if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == FEAT_CRAFT_WAND) sBaseName = "Wand"; + else sBaseName = ai_StripColorCodes(GetName(GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + int nUses = ai_GetItemUses(oItem, nIprpSubType); + if(nUses) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(nUses == 999) sText = "Unlimited"; + else sText = IntToString(nUses); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")")); + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + else jWidget = JsonArrayDel(jWidget, nIndex--); + } + else if(nFeat) // This is a feat. + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + sSpellIcon = ""; + if(nSpell) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + if(sSpellIcon == "" || sSpellIcon == "IR_USE") + { + sName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + sSpellIcon = Get2DAString("feat", "ICON", nFeat); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + if(GetHasFeat(nFeat, oAssociate)) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName)); + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + else // This is a spell. + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + //SendMessageToPC(oPC, GetName(oAssociate) + " nSpell: " + IntToString(nSpell) + + // " nClass: " + IntToString(nClass) + " nMetaMagic: " + IntToString(nMetaMagic) + + // " nDomain: " + IntToString(nDomain) + " nLevel: " + IntToString(nLevel)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + sSubSpell = Get2DAString("spells", "Master", nSpell); + if(sSubSpell != "") nSpell = StringToInt(sSubSpell); + if(nDomain == -1 || GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain)) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(nDomain == -1) NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName)); + else + { + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + } + } + else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + } + else break; + ++nIndex; + } + } + } +} +void ai_CreateWidgetNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + if(sAssociateType == "") return; + int bAIWidgetLock = ai_GetWidgetButton(oPC, BTN_WIDGET_LOCK, oAssociate, sAssociateType); + int bVertical = ai_GetWidgetButton(oPC, BTN_WIDGET_VERTICAL, oAssociate, sAssociateType); + float fButtons; + // ************************************************************************* Width / Height + // Row 1 (buttons)********************************************************** + // Setup the main associate button to use their portrait. + json jButton = NuiEnabled(NuiId (NuiButtonImage(NuiBind("btn_open_main_image")), "btn_open_main"), NuiBind("btn_open_main_event")); + jButton = NuiWidth(jButton, 35.0); + jButton = NuiHeight(jButton, 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind ("btn_open_main_tooltip")); + jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 32.0, 35.0)); + json jRow = JsonArrayInsert(JsonArray(), jButton); + if(ai_GetWidgetButton(oPC, BTN_CMD_ACTION, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_action", "btn_cmd_action", 35.0f, 35.0f, 0.0, "btn_cmd_action_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_GUARD, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_guard", "btn_cmd_guard", 35.0f, 35.0f, 0.0, "btn_cmd_guard_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_HOLD, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_standground", "btn_cmd_hold", 35.0f, 35.0f, 0.0, "btn_cmd_hold_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_ATTACK, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_attacknearest", "btn_cmd_attack", 35.0f, 35.0f, 0.0, "btn_cmd_attack_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_FOLLOW, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_follow", "btn_cmd_follow", 35.0f, 35.0f, 0.0, "btn_cmd_follow_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_FOLLOW_TARGET, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_dmchat", "btn_follow_target", 35.0f, 35.0f, 0.0, "btn_follow_target_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_SEARCH, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ife_foc_search", "btn_cmd_search", 35.0f, 35.0f, 0.0, "btn_cmd_search_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_STEALTH, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ife_foc_hide", "btn_cmd_stealth", 35.0f, 35.0f, 0.0, "btn_cmd_stealth_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_AI_SCRIPT, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "", "btn_cmd_ai_script", 35.0f, 35.0f, 0.0, "btn_cmd_ai_script_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_PLACE_TRAP, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_settrap", "btn_cmd_place_trap", 35.0f, 35.0f, 0.0, "btn_cmd_place_trap_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_SHORT, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_cantrips", "btn_buff_short", 35.0f, 35.0f, 0.0, "btn_buff_short_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_LONG, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_cast", "btn_buff_long", 35.0f, 35.0f, 0.0, "btn_buff_long_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_ALL, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_level789", "btn_buff_all", 35.0f, 35.0f, 0.0, "btn_buff_all_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_BUFF_REST, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_rest", "btn_buff_rest", 35.0f, 35.0f, 0.0, "btn_buff_rest_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_JUMP_TO, oAssociate, sAssociateType)) + { + string sImage; + if(oPC == oAssociate) sImage = "dm_jumpall"; + else sImage = "dm_jump"; + jRow = CreateButtonImage(jRow, sImage, "btn_jump_to", 35.0f, 35.0f, 0.0, "btn_jump_to_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_GHOST_MODE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "dm_limbo", "btn_ghost_mode", 35.0f, 35.0f, 0.0, "btn_ghost_mode_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_CAMERA, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_examine", "btn_camera", 35.0f, 35.0f, 0.0, "btn_camera_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_INVENTORY, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_pickup", "btn_inventory", 35.0f, 35.0f, 0.0, "btn_inventory_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_FAMILIAR, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ife_familiar", "btn_familiar", 35.0f, 35.0f, 0.0, "btn_familiar_tooltip"); + fButtons += 1.0; + } + if(ai_GetWidgetButton(oPC, BTN_CMD_COMPANION, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ife_animal", "btn_companion", 35.0f, 35.0f, 0.0, "btn_companion_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_FOR_PC, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "dm_ai", "btn_ai", 35.0f, 35.0f, 0.0, "btn_ai_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_REDUCE_SPEECH, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_movsilent", "btn_quiet", 35.0f, 35.0f, 0.0, "btn_quiet_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_USE_RANGED, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_archer", "btn_ranged", 35.0f, 35.0f, 0.0, "btn_ranged_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_WEAPON_EQUIP, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "dm_takeitem", "btn_equip_weapon", 35.0f, 35.0f, 0.0, "btn_equip_weapon_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_USE_SEARCH, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_search", "btn_search", 35.0f, 35.0f, 0.0, "btn_search_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_USE_STEALTH, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_hide", "btn_stealth", 35.0f, 35.0f, 0.0, "btn_stealth_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_OPEN_DOORS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_open", "btn_open_door", 35.0f, 35.0f, 0.0, "btn_open_door_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_REMOVE_TRAPS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_distrap", "btn_traps", 35.0f, 35.0f, 0.0, "btn_traps_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_PICK_LOCKS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_olock", "btn_pick_locks", 35.0f, 35.0f, 0.0, "btn_pick_locks_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_BASH_LOCKS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_bash", "btn_bash_locks", 35.0f, 35.0f, 0.0, "btn_bash_locks_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_MAGIC_LEVEL, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "dm_control", "btn_magic_level", 35.0f, 35.0f, 0.0, "btn_magic_level_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_NO_SPONTANEOUS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_xability", "btn_spontaneous", 35.0f, 35.0f, 0.0, "btn_spontaneous_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_USE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_cntrspell", "btn_magic", 35.0f, 35.0f, 0.0, "btn_magic_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_NO_MAGIC_ITEM_USE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_moreattacks", "btn_magic_items", 35.0f, 35.0f, 0.0, "btn_magic_items_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_DEF_MAGIC_USE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_orisons", "btn_def_magic", 35.0f, 35.0f, 0.0, "btn_def_magic_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_OFF_MAGIC_USE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_metamagic", "btn_off_magic", 35.0f, 35.0f, 0.0, "btn_off_magic_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_HEAL_OUT, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "isk_heal", "btn_heal_out", 35.0f, 35.0f, 0.0, "btn_heal_out_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_HEAL_IN, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "dm_heal", "btn_heal_in", 35.0f, 35.0f, 0.0, "btn_heal_in_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_SELF_HEALING, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_heal", "btn_heals_onoff", 35.0f, 35.0f, 0.0, "btn_heals_onoff_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_PARTY_HEALING, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_party", "btn_healp_onoff", 35.0f, 35.0f, 0.0, "btn_healp_onoff_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_STOP_CURE_SPELLS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_accept", "btn_cure_onoff", 35.0f, 35.0f, 0.0, "btn_cure_onoff_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_LOOT, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_barter", "btn_loot", 35.0f, 35.0f, 0.0, "btn_loot_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_IGNORE_ASSOCIATES, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_ignore", "btn_ignore_assoc", 35.0f, 35.0f, 0.0, "btn_ignore_assoc_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_IGNORE_TRAPS, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_abort", "btn_ignore_traps", 35.0f, 35.0f, 0.0, "btn_ignore_traps_tooltip"); + fButtons += 1.0; + } + if(ai_GetAIButton(oPC, BTN_AI_PERC_RANGE, oAssociate, sAssociateType)) + { + jRow = CreateButtonImage(jRow, "ir_dmchat", "btn_perc_range", 35.0f, 35.0f, 0.0, "btn_perc_range_tooltip"); + fButtons += 1.0; + } + int bIsPC = ai_GetIsCharacter(oAssociate); + if(bIsPC) + { + json jPCPlugins = ai_UpdatePluginsForPC(oPC); + // Plug in buttons ***************************************************** + int nIndex, bWidget; + string sIcon, sButton; + json jPlugin = JsonArrayGet(jPCPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bWidget == 1) + { + sIcon = JsonGetString(JsonArrayGet(jPlugin, 3)); + sButton = IntToString(nIndex); + jRow = CreateButtonImage(jRow, sIcon, "btn_exe_plugin_" + sButton, 35.0f, 35.0f, 0.0, "btn_exe_plugin_" + sButton + "_tooltip"); + fButtons += 1.0; + } + jPlugin = JsonArrayGet(jPCPlugins, ++nIndex); + } + } + float fHeight, fWidth; + if(bAIWidgetLock) + { + fWidth = 50.0f; + fHeight = 50.0; + } + else if(bVertical) + { + fWidth = 88.0f; + fHeight = 55.0f; + } + else + { + fWidth = 55.0f; + fHeight = 88.0f; + } + // Quick Widget. + int nIndex, nSpell, nLevel, nMetaMagic; + float fQuickWidgetColumns; + string sClass, sLevel, sIndex; + object oItem; + json jSpell; + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jCol = JsonArray(); + if(ai_GetWidgetButton(oPC, BTN_CMD_SPELL_WIDGET, oAssociate, sAssociateType) && + JsonGetLength(jWidget) > 0) + { + // Row 2 (Widget Row 1)************************************************* + if(JsonGetType(jWidget) != JSON_TYPE_NULL) + { + fQuickWidgetColumns += 1.0; + int bAdd; + float fSpellButtons; + json jButton, jRectangle, jMetaMagic, jDrawList; + // Add row to the column. + if(bVertical) jCol = JsonArrayInsert(jCol, NuiCol(jRow)); + else jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + jRow = CreateButtonImage(JsonArray(), "ir_back", "btn_update_widget", 35.0f, 35.0f, 0.0, "btn_update_widget_tooltip"); + //CreateLabel(jRow, "", "blank_label", 35.0, 35.0, 0, 0, 0.0); + while(nIndex < 10) + { + bAdd = TRUE; + jSpell = JsonArrayGet(jWidget, nIndex); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + if(JsonGetInt(JsonArrayGet(jSpell, 1)) == -1) + { + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + if(oItem == OBJECT_INVALID) + { + bAdd = FALSE; + jWidget = JsonArrayDel(jWidget, nIndex--); + jSpells = JsonArrayInsert(jSpells, jWidget, 2); + jAIData = JsonArrayInsert(jAIData, jSpells, 10); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + } + if(bAdd) + { + sIndex = IntToString(nIndex); + jButton = NuiButtonImage(NuiBind("btn_widget_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_widget_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_widget_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip")); + jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + fSpellButtons += 1.0; + } + } + else break; + ++nIndex; + } + if(fSpellButtons > fButtons) fButtons = fSpellButtons; + // Row 3 (Widget Row 2)************************************************* + if(nIndex > 9 && JsonGetLength(jWidget) > 10) + { + fQuickWidgetColumns += 1.0; + // Add row to the column. + if(bVertical) jCol = JsonArrayInsert(jCol, NuiCol(jRow)); + else jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + jRow = CreateLabel(JsonArray(), "", "blank_label", 35.0, 35.0, 0, 0, 0.0); + while(nIndex < 20) + { + jSpell = JsonArrayGet(jWidget, nIndex); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + if(JsonGetInt(JsonArrayGet(jSpell, 1)) == -1) + { + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + if(oItem == OBJECT_INVALID) + { + bAdd = FALSE; + jWidget = JsonArrayDel(jWidget, nIndex--); + jSpells = JsonArrayInsert(jSpells, jWidget, 2); + jAIData = JsonArrayInsert(jAIData, jSpells, 10); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + } + if(bAdd) + { + sIndex = IntToString(nIndex); + jButton = NuiButtonImage(NuiBind("btn_widget_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_widget_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_widget_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip")); + jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + fSpellButtons += 1.0; + } + } + else break; + ++nIndex; + } + } + } + // Add the row to the column. + if(nIndex > 0) + { + if(bVertical) jCol = JsonArrayInsert(jCol, NuiCol(jRow)); + else jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + } + } + else + { + // Add the row to the column. + if(bVertical) jCol = JsonArrayInsert(jCol, NuiCol(jRow)); + else jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + } + float fScale = GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE) / 100.0; + float fButtonScale; + // 1.1 = 2.5 2.0 = 6.0 Ranges we need for scales to work correctly. + if(fScale > 1.0) fButtonScale = (fScale - 1.1) / (2.0 - 1.1) * 3.5 + 2.5; + else fButtonScale = 1.0; + if(fButtons > 0.0f) + { + if(bVertical) fWidth = fWidth + fButtons * 35.0f + fButtons * fButtonScale; + else fWidth = fWidth + fButtons * 35.0f; + } + if(fQuickWidgetColumns > 0.0f) + { + if(bVertical) fHeight = fHeight + fQuickWidgetColumns * 39.0f; + else fHeight = fHeight + fQuickWidgetColumns * 39.0f + fQuickWidgetColumns * fButtonScale; + } + // Get the window location to restore it from the database. + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + //SendMessageToPC(oPC, "0i_menu, 2124, sAssociateType: " + sAssociateType + " jLocations: " + JsonDump(jLocations, 1)); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) + { + ai_SetupAssociateData(oPC, oAssociate, sAssociateType); + jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + } + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_WIDGET_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Keeps the widgets from bunching up in the top corner. + if(fY == 0.0 && fX == 0.0) + { + if(sAssociateType == "pc") fY = 1.0; + else if(sAssociateType == "familiar") fY = 96.0 * fScale; + else if(sAssociateType == "companion") fY = 192.0 * fScale; + else if(sAssociateType == "summons") fY = 288.0 * fScale; + else if(sAssociateType == "dominated") fY = 384.0 * fScale; + else + { + int nIndex = 1; + string sAssociateName = GetName(oAssociate); + while(nIndex < AI_MAX_HENCHMAN) + { + if(sAssociateName == GetName(GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex))) + { + fY = (88.0 + 88.0 * IntToFloat(nIndex - 1)); + break; + } + nIndex++; + } + } + fY = fY * fScale; + } + if(bAIWidgetLock) + { + fX += 4.0f; + // GUI scales are a mess, I just figured them out per scale to keep the widget from moving. + if(fScale == 1.0) fY += 37.0; + else if(fScale == 1.1) fY += 38.0; + else if(fScale == 1.2) fY += 40.0; + else if(fScale == 1.3) fY += 42.0; + else if(fScale == 1.4) fY += 43.0; + else if(fScale == 1.5) fY += 45.0; + else if(fScale == 1.6) fY += 47.0; + else if(fScale == 1.7) fY += 48.0; + else if(fScale == 1.8) fY += 50.0; + else if(fScale == 1.9) fY += 52.0; + else if(fScale == 2.0) fY += 54.0; + } + // Set the layout of the window. + json jLayout; + int nToken, bBool; + string sHeal, sText, sRange; + string sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + if(bVertical) + { + jLayout = NuiRow(jCol); + if(bAIWidgetLock) nToken = SetWindow(oPC, jLayout, sAssociateType + AI_WIDGET_NUI, "AI Widget", fX, fY, fHeight, fWidth, FALSE, FALSE, FALSE, TRUE, FALSE, "0e_nui"); + else nToken = SetWindow(oPC, jLayout, sAssociateType + AI_WIDGET_NUI, sName + " Widget", fX, fY, fHeight, fWidth, FALSE, FALSE, FALSE, TRUE, TRUE, "0e_nui"); +} + else + { + jLayout = NuiCol(jCol); + if(bAIWidgetLock) nToken = SetWindow(oPC, jLayout, sAssociateType + AI_WIDGET_NUI, "AI Widget", fX, fY, fWidth, fHeight, FALSE, FALSE, FALSE, TRUE, FALSE, "0e_nui"); + else nToken = SetWindow(oPC, jLayout, sAssociateType + AI_WIDGET_NUI, sName + " Widget", fX, fY, fWidth, fHeight, FALSE, FALSE, FALSE, TRUE, TRUE, "0e_nui"); + } + // Save the associate to the nui. + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + NuiSetUserData(oPC, nToken, jData); + ai_SetWidgetBinds(oPC, oAssociate, sAssociateType, nToken, sName); +} +json ai_CreateLootFilterRow(json jRow, string sLabel, int nIndex) +{ + string sIndex = IntToString(nIndex); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateTextEditBox(jRow, "plc_hold", "txt_gold_" + sIndex, 9, FALSE, 90.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateCheckBox(jRow, sLabel, "chbx_" + sIndex, 200.0, 20.0); + return JsonArrayInsert(jRow, NuiSpacer()); +} +void ai_SetupLootElements(object oPC, object oAssociate, int nToken, int nLootBit, int nIndex) +{ + string sIndex = IntToString(nIndex); + int bLoot = ai_GetLootFilter(oAssociate, nLootBit); + NuiSetBind(oPC, nToken, "chbx_" + sIndex + "_check", JsonBool(bLoot)); + NuiSetBindWatch (oPC, nToken, "chbx_" + sIndex + "_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_" + sIndex + "_event", JsonBool(TRUE)); + string sGold = IntToString(GetLocalInt(oAssociate, AI_MIN_GOLD_ + sIndex)); + NuiSetBind(oPC, nToken, "txt_gold_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_gold_" + sIndex, JsonString(sGold)); + NuiSetBindWatch (oPC, nToken, "txt_gold_" + sIndex, TRUE); +} +void ai_CreateLootFilterNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 318 / 73 + int bIsPC = ai_GetIsCharacter(oAssociate); + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateCheckBox(jRow, "Give all loot to the player", "chbx_give_loot", 200.0, 20.0, "chbx_give_loot_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 *************************************************************** 388 / 101 + jRow = JsonArray(); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateTextEditBox(jRow, "plc_hold", "txt_max_weight", 9, FALSE, 50.0, 20.0, "txt_max_weight_tooltip"); + jRow = CreateLabel(jRow, "Maximum Weight to pickup", "lbl_weight", 200.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 *************************************************************** 388 / 129 + jRow = JsonArray(); + jRow = CreateButton(jRow, "Set All", "btn_set_all", 110.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear All", "btn_clear_all", 110.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 *************************************************************** 388 / 157 + jRow = JsonArray(); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "Minimum Gold", "lbl_min_gold", 100.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateLabel(jRow, "Items to Pickup", "lbl_pickup", 140.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 *************************************************************** 388 / 185 + jRow = ai_CreateLootFilterRow(JsonArray(), "Plot items", 2); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 6 *************************************************************** 388 / 213 + jRow = ai_CreateLootFilterRow(JsonArray(), "Armor", 3); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 7 *************************************************************** 388 / 241 + jRow = ai_CreateLootFilterRow(JsonArray(), "Belts", 4); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 8 *************************************************************** 388 / 269 + jRow = ai_CreateLootFilterRow(JsonArray(), "Boots", 5); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 9 *************************************************************** 388 / 297 + jRow = ai_CreateLootFilterRow(JsonArray(), "Cloaks", 6); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 10 *************************************************************** 388 / 325 + jRow = ai_CreateLootFilterRow(JsonArray(), "Gems", 7); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 11 *************************************************************** 388 / 353 + jRow = ai_CreateLootFilterRow(JsonArray(), "Gloves and Bracers", 8); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 12 *************************************************************** 388 / 381 + jRow = ai_CreateLootFilterRow(JsonArray(), "Headgear", 9); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 13 *************************************************************** 388 / 409 + jRow = ai_CreateLootFilterRow(JsonArray(), "Jewelry", 10); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 14 *************************************************************** 388 / 437 + jRow = ai_CreateLootFilterRow(JsonArray(), "Miscellaneous items", 11); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 15 *************************************************************** 388 / 465 + jRow = ai_CreateLootFilterRow(JsonArray(), "Potions", 12); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 16 *************************************************************** 388 / 493 + jRow = ai_CreateLootFilterRow(JsonArray(), "Scrolls", 13); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 17 *************************************************************** 388 / 521 + jRow = ai_CreateLootFilterRow(JsonArray(), "Shields", 14); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 18 *************************************************************** 388 / 549 + jRow = ai_CreateLootFilterRow(JsonArray(), "Wands, Rods, and Staves", 15); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 19 ************************************************************** 388 / 577 + jRow = ai_CreateLootFilterRow(JsonArray(), "Weapons", 16); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 20 ************************************************************** 388 / 605 + jRow = ai_CreateLootFilterRow(JsonArray(), "Arrows", 17); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 21 ************************************************************** 388 / 633 + jRow = ai_CreateLootFilterRow(JsonArray(), "Bolts", 18); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 22 ************************************************************** 388 / 661 + jRow = ai_CreateLootFilterRow(JsonArray(), "Bullets", 19); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_LOOTFILTER_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sText, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_LOOTFILTER_NUI, sName + " Loot Filter", + fX, fY, 318.0, 673.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Save the associate to the nui. + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + NuiSetUserData(oPC, nToken, jData); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 + int bGiveLoot = ai_GetLootFilter(oAssociate, AI_LOOT_GIVE_TO_PC); + NuiSetBind(oPC, nToken, "chbx_give_loot_check", JsonBool (bGiveLoot)); + NuiSetBindWatch (oPC, nToken, "chbx_give_loot_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_give_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_give_loot_tooltip", JsonString( + " Check this to make henchman give any loot picked up to the player.")); + // Row 2 + int nWeight = GetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT); + if(nWeight == 0) + { + nWeight = 200; + SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, nWeight); + } + NuiSetBind(oPC, nToken, "txt_max_weight_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_max_weight", JsonString(IntToString(nWeight))); + NuiSetBindWatch (oPC, nToken, "txt_max_weight", TRUE); + NuiSetBind(oPC, nToken, "txt_max_weight_tooltip", JsonString(" Max weighted item you will pickup from 1 to 1,000")); + // Row 3 + NuiSetBind(oPC, nToken, "btn_set_all_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_set_all", JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_all_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_all", JsonInt(TRUE)); + // Row 4 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_PLOT, 2); + // Row 5 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_ARMOR, 3); + // Row 6 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_BELTS, 4); + // Row 7 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_BOOTS, 5); + // Row 8 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_CLOAKS, 6); + // Row 9 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_GEMS, 7); + // Row 10 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_GLOVES, 8); + // Row 11 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_HEADGEAR, 9); + // Row 12 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_JEWELRY, 10); + // Row 13 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_MISC, 11); + // Row 14 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_POTIONS, 12); + // Row 15 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_SCROLLS, 13); + // Row 16 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_SHIELDS, 14); + // Row 17 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_WANDS_RODS_STAVES, 15); + // Row 18 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_WEAPONS, 16); + // Row 19 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_ARROWS, 17); + // Row 20 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_BOLTS, 18); + // Row 21 + ai_SetupLootElements(oPC, oAssociate, nToken, AI_LOOT_BULLETS, 19); +} +void ai_CreateCopySettingsNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 244 / 73 + string sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "Copy settings to", "lbl_paste", 220.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 244 / 101 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "All Associates", "btn_paste_all", 220.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 2 ******************************************************************* 244 / 129 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Familiar", "btn_paste_familiar", 220.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 244 / 157 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Companion", "btn_paste_companion", 220.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 244 / 185 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Summons", "btn_paste_summons", 220.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 ******************************************************************* 244 / 213 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Dominated", "btn_paste_dominated", 220.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5+ ****************************************************************** 244 / 241 + float fHeight = 241.0; + int nIndex; + string sAssocName; + object oAssoc; + for(nIndex = 1; nIndex < AI_MAX_HENCHMAN; nIndex++) + { + oAssoc = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssoc != OBJECT_INVALID) + { + sAssocName = GetName(oAssoc); + if(GetStringRight(sAssocName, 1) == "s") sAssocName = sAssocName + "'"; + else sAssocName = sAssocName + "'s"; + jRow = CreateButton(JsonArray(), sAssocName, "btn_paste_henchman" + IntToString(nIndex), 220.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + else break; + } + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_COPY_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_COPY_NUI, sName + " Copy Settings Menu", + fX, fY, 244.0, fHeight + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Save the associate to the nui. + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + NuiSetUserData(oPC, nToken, jData); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 + NuiSetBind(oPC, nToken, "btn_paste_all_event", JsonBool (TRUE)); + oAssoc = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC); + NuiSetBind(oPC, nToken, "btn_paste_familiar_event", JsonBool(oAssoc != oAssociate && oAssoc != OBJECT_INVALID)); + oAssoc = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC); + NuiSetBind(oPC, nToken, "btn_paste_companion_event", JsonBool(oAssoc != oAssociate && oAssoc != OBJECT_INVALID)); + oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC); + NuiSetBind(oPC, nToken, "btn_paste_summons_event", JsonBool(oAssoc != oAssociate && oAssoc != OBJECT_INVALID)); + oAssoc = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC); + NuiSetBind(oPC, nToken, "btn_paste_dominated_event", JsonBool(oAssoc != oAssociate && oAssoc != OBJECT_INVALID)); + for(nIndex = 1; nIndex < AI_MAX_HENCHMAN; nIndex++) + { + oAssoc = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssoc != OBJECT_INVALID) + { + NuiSetBind(oPC, nToken, "btn_paste_henchman" + IntToString(nIndex) + "_event", JsonBool(oAssoc != oAssociate)); + } + else break; + } +} +void ai_CreatePluginNUI(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int nIndex, nButton; + string sButton; + // Row 1 ******************************************************************* 500 / 73 + json jRow = CreateButton(JsonArray(), "Load Plugins", "btn_load_plugins", 150.0f, 20.0f, -1.0, "btn_load_plugins_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Load Monster Mods", "btn_load_m_mods", 150.0f, 20.0f, -1.0, "btn_load_m_mods_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Check All", "btn_check_plugins", 80.0f, 20.0f, -1.0, "btn_check_plugins_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear All", "btn_clear_plugins", 80.0f, 20.0f, -1.0, "btn_clear_plugins_tooltip"); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 101 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Add Plugin", "btn_add_plugin", 150.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateTextEditBox(jRow, "sPlaceHolder", "txt_plugin", 16, FALSE, 310.0f, 20.0f, "txt_plugin_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 101.0; + // Row 3+ ****************************************************************** 500 / --- + json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins"); + nIndex = 0; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + string sName; + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Remove Plugin", "btn_remove_plugin_" + sButton, 150.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(jRow, sName, "btn_plugin_" + sButton, 290.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + // Get the window location to restore it from the database. + json jLocations = ai_GetAssociateDbJson(oPC, "pc", "locations"); + float fX, fY; + jLocations = JsonObjectGet(jLocations, AI_PLUGIN_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, AI_PLUGIN_NUI, sName + " PEPS Plugin Manager", + fX, fY, 500.0f, fHeight + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oPC))); + NuiSetUserData(oPC, nToken, jData); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Row 1 + NuiSetBind(oPC, nToken, "btn_load_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_load_plugins_tooltip", JsonString(" Load all known PEPS plugins that are in the game files.")); + NuiSetBind(oPC, nToken, "btn_load_m_mods_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_load_m_mods_tooltip", JsonString(" Load all known PEPS monster mods that are in the game files.")); + NuiSetBind(oPC, nToken, "btn_check_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_check_plugins_tooltip", JsonString(" Add all plugins to the players widget.")); + NuiSetBind(oPC, nToken, "btn_clear_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_plugins_tooltip", JsonString(" Remove all plugins from the players widget.")); + // Row 2 + NuiSetBind(oPC, nToken, "btn_add_plugin_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_plugin_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_plugin_tooltip", JsonString(" Enter an executable script name.")); + // Row 3+ + nIndex = 0; + int bCheck; + string sText; + jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_remove_plugin_" + sButton + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_event", JsonBool(TRUE)); + bCheck = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bCheck < 3) + { + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_check", JsonBool(bCheck)); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_plugin_" + sButton + "_check", TRUE); + } + sText = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_tooltip", JsonString(sText)); + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } +} +int ai_SpellNotInList(int nSpell, json jSpellArray) +{ + int nMaxArray = JsonGetLength(jSpellArray); + int nIndex; + while(nIndex < nMaxArray) + { + if(nSpell == JsonGetInt(JsonArrayGet(JsonArrayGet(jSpellArray, nIndex), 0))) return FALSE; + nIndex++; + } + return TRUE; +} +json ai_CheckItemAbilities(json jQuickListArray, object oCreature, object oItem, json jSpell_Icon, json jSpell_Text, int bEquiped = FALSE) +{ + // We have established that we can use the item if it is equiped. + if(!bEquiped && !ai_CheckIfCanUseItem(oCreature, oItem)) return jQuickListArray; + int nPerDay, nCharges, nUses, bSaveTalent, nBaseItemType; + int nIprpSubType, nSpell, nLevel, nIPType, nIndex; + string sSpellIcon, sSpellName; + itemproperty ipProp = GetFirstItemProperty(oItem); + json jSpell; + // Lets skip this if there are no properties. + if(!GetIsItemPropertyValid(ipProp)) return jQuickListArray; + // Check for cast spell property and add them to the talent list. + while(GetIsItemPropertyValid(ipProp)) + { + nIPType = GetItemPropertyType(ipProp); + if(nIPType == ITEM_PROPERTY_CAST_SPELL) + { + bSaveTalent = TRUE; + // Get how they use the item (charges or uses per day). + nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses > 1 && nUses < 7) + { + nCharges = GetItemCharges(oItem); + if((nUses == IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE && nCharges < 1) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE && nCharges < 2) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_3_CHARGES_PER_USE && nCharges < 3) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_4_CHARGES_PER_USE && nCharges < 4) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_5_CHARGES_PER_USE && nCharges < 5)) bSaveTalent = FALSE; + } + else if(nUses > 7 && nUses < 13) + { + nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(AI_DEBUG) ai_Debug("0i_talents", "1676", "Item uses: " + IntToString(nPerDay)); + if(nPerDay == 0) bSaveTalent = FALSE; + } + if(bSaveTalent) + { + // SubType is the ip spell index for iprp_spells.2da + nIprpSubType = GetItemPropertySubType(ipProp); + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + nBaseItemType = GetBaseItemType(oItem); + if(nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL) + { + sSpellIcon = Get2DAString("iprp_spells", "Icon", nIprpSubType); + sSpellName = ai_StripColorCodes(GetName(oItem)); + nUses = GetNumStackedItems(oItem); + } + else + { + if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) + { + sSpellName = ai_StripColorCodes(GetName(oItem)); + nUses = GetNumStackedItems(oItem); + } + else if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == FEAT_CRAFT_WAND) + { + sSpellName = ai_StripColorCodes(GetName(oItem)); + nUses = nCharges; + } + else + { + sSpellName = ai_StripColorCodes(GetName(oItem)) + ": "; + sSpellName += GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(nCharges) nUses = nCharges; + else nUses = nPerDay; + } + sSpellIcon = Get2DAString("spells", "iConResRef", nSpell); + } + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(-1)); // Class is set to -1 for items + jSpell = JsonArrayInsert(jSpell, JsonInt(nUses)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nBaseItemType)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nIprpSubType)); + jSpell = JsonArrayInsert(jSpell, JsonString(GetObjectUUID(oItem))); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + else if(nIPType == ITEM_PROPERTY_HEALERS_KIT) + { + // Must also have ranks in healing kits. + if(GetSkillRank(SKILL_HEAL, oCreature) > 0) + { + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString("isk_heal")); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(ai_StripColorCodes(GetName(oItem)))); + json jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(SPELL_HEALINGKIT)); + jSpell = JsonArrayInsert(jSpell, JsonInt(-1)); // Class is set to -1 for items + jSpell = JsonArrayInsert(jSpell, JsonInt(GetNumStackedItems(oItem))); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jSpell = JsonArrayInsert(jSpell, JsonInt(GetItemPropertyCostTableValue(ipProp))); + jSpell = JsonArrayInsert(jSpell, JsonString(GetObjectUUID(oItem))); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + nIndex++; + ipProp = GetNextItemProperty(oItem); + } + SetLocalJson(oCreature, "JSPELL_ICON", jSpell_Icon); + SetLocalJson(oCreature, "JSPELL_NAME", jSpell_Text); + return jQuickListArray; +} +void ai_CreateQuickWidgetSelectionNUI(object oPC, object oAssociate) +{ + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + json jRow = JsonArray(); + // Row 1 Classes************************************************************ 414 / 88 + int nClass, nLevel, nIndex; + string sIndex, sClassIcon, sLevelIcon; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass != CLASS_TYPE_INVALID) + { + // This saves the class position in the button id so we can get it later. + sIndex = IntToString(nIndex); + sClassIcon = Get2DAString("classes", "Icon", nClass); + jRow = CreateButtonImage(jRow, sClassIcon, "btn_class_" + sIndex, 35.0f, 35.0f, 0.0, "btn_class_" + sIndex + "_tooltip"); + } + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Levels) ********************************************************** 414 / 131 + jRow = CreateButtonImage(JsonArray(), "", "btn_level_11" , 35.0f, 35.0f, 0.0, "btn_level_11_tooltip"); + jRow = CreateButtonImage(jRow, "", "btn_level_10" , 35.0f, 35.0f, 0.0, "btn_level_10_tooltip"); + for(nIndex = 0; nIndex <= 9; nIndex++) + { + // This saves the level in the button id so we can get it later. + sIndex = IntToString(nIndex); + jRow = CreateButtonImage(jRow, "", "btn_level_" + sIndex, 35.0f, 35.0f, 0.0, "btn_level_" + sIndex + "_tooltip"); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Spell List)******************************************************* 414 / 433 + json jButton = JsonArray(); + jButton = NuiButton(NuiBind("text_spell")); + jButton = NuiId(jButton, "btn_text_spell"); + json jRectangle = NuiRect(4.0, 4.0, 27.0, 27.0); + json jDrawList = JsonArrayInsert(JsonArray(), NuiDrawListImage(JsonBool(TRUE), NuiBind("icon_spell"), jRectangle, JsonInt(NUI_ASPECT_FILL), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_MIDDLE))); + jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_text")); + jDrawList = JsonArrayInsert(jDrawList, jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + json jListTemplate = JsonArrayInsert(JsonArray(), NuiListTemplateCell(jButton, 345.0, FALSE)); + json jInfo = NuiButtonImage(JsonString("gui_cg_qstn_mark")); + jInfo = NuiId(jInfo, "btn_info_spell"); + jListTemplate = JsonArrayInsert(jListTemplate, NuiListTemplateCell(jInfo, 35.0, FALSE)); + jRow = JsonArrayInsert(JsonArray(), NuiHeight(NuiList(jListTemplate, NuiBind("icon_spell"), 35.0), 282.0)); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (Widget Label)***************************************************** 414 / 461 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "Quick Widget List", "lbl_quick_list", 150.0, 20.0, 0, 0, 0.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 (Widget row 1)***************************************************** 414 / 504 + jRow = JsonArray(); + for(nIndex = 0; nIndex < 10; nIndex++) + { + // This saves the index location in the json jWidget in the button id for later use. + sIndex = IntToString(nIndex); + json jButton = NuiButtonImage(NuiBind("btn_widget_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_widget_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_widget_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip")); + json jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 6 (Widget row 2)***************************************************** 414 / 543 + jRow = JsonArray(); + for(nIndex = 10; nIndex < 20; nIndex++) + { + // This saves the index location in the json jWidget in the button id for later use. + sIndex = IntToString(nIndex); + json jButton = NuiButtonImage(NuiBind("btn_widget_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_widget_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_widget_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip")); + json jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_QUICK_WIDGET_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sText, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_QUICK_WIDGET_NUI, sName + " Quick Widget Menu", + fX, fY, 414.0, 543.0 + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Set the Layout of the window. + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + json jSpells; + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + // Temporary fix for error! :/ + if(JsonGetLength(jAIData) == 0) + { + ai_CheckAssociateData(oPC, oAssociate, sAssociateType, TRUE); + jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(10)); + jAIData = JsonArrayInsert(jAIData, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + nLevel = 10; + } + if(JsonGetLength(jAIData) == 9) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(10)); + jSpells = JsonArrayInsert(jSpells, JsonArray()); + jAIData = JsonArrayInsert(jAIData, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + nLevel = 10; + } + else + { + jSpells = JsonArrayGet(jAIData, 10); + if(JsonGetLength(jSpells) == 0) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(10)); + jSpells = JsonArrayInsert(jSpells, JsonArray()); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + nLevel = 10; + } + else + { + nClass = JsonGetInt(JsonArrayGet(jSpells, 0)); + nLevel = JsonGetInt(JsonArrayGet(jSpells, 1)); + } + } + if(nClass < 1 || nClass > AI_MAX_CLASSES_PER_CHARACTER) nClass = 1; + nClass = GetClassByPosition(nClass, oAssociate); + // Row 1 & 2 Class & Level + int nSpellLevel, nLevelIndex, nClassIndex, nMaxSpellLevel; + string sClass, sLevel, sLevelImage, sLevelIndex; + NuiSetBind(oPC, nToken, "btn_level_11_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_11_tooltip", JsonString(" Item Powers")); + NuiSetBind(oPC, nToken, "btn_level_11_image", JsonString("ir_attack")); + NuiSetBind(oPC, nToken, "btn_level_10_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_10_tooltip", JsonString(" Special Abilities")); + NuiSetBind(oPC, nToken, "btn_level_10_image", JsonString("dm_god")); + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClassIndex = GetClassByPosition(nIndex, oAssociate); + if(nClassIndex != CLASS_TYPE_INVALID) + { + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClassIndex))); + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_tooltip", JsonString(" " + sClass)); + if(nClass == nClassIndex) + { + if(StringToInt(Get2DAString("classes", "SpellCaster", nClass))) + { + int nClassLevel = GetLevelByClass(nClass, oAssociate); + string sSpellsGained = Get2DAString("classes", "SpellGainTable", nClass); + int nMaxSpellLevel = StringToInt(Get2DAString(sSpellsGained, "NumSpellLevels", nClassLevel - 1)); + for(nLevelIndex = 0; nLevelIndex <= 9; nLevelIndex++) + { + sLevelIndex = IntToString(nLevelIndex); + if(nLevelIndex < nMaxSpellLevel) + { + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_event", JsonBool(TRUE)); + if(nLevelIndex == 0) sLevelImage = "ir_cantrips"; + else if(nLevelIndex < 7)sLevelImage = "ir_level" + sLevelIndex; + else sLevelImage = "ir_level789"; + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_image", JsonString(sLevelImage)); + if(nLevelIndex == 0) sLevel = " Cantrips"; + else if(nLevelIndex == 1) sLevel = " First level"; + else if(nLevelIndex == 2) sLevel = " Second level"; + else if(nLevelIndex == 3) sLevel = " Third level"; + else if(nLevelIndex == 4) sLevel = " Fourth level"; + else if(nLevelIndex == 5) sLevel = " Fifth level"; + else if(nLevelIndex == 6) sLevel = " Sixth level"; + else if(nLevelIndex == 7) sLevel = " Seventh level"; + else if(nLevelIndex == 8) sLevel = " Eighth level"; + else if(nLevelIndex == 9) sLevel = " Ninth level"; + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_tooltip", JsonString(" " + sLevel)); + } + else + { + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_event", JsonBool(FALSE)); + } + } + NuiSetBind(oPC, nToken, "btn_level_" + IntToString(nLevel) + "_encouraged", JsonBool(TRUE)); + } + // Default to the abilities tab since they are not a caster. + else + { + if(nLevel < 10) nLevel = 10; + for(nLevelIndex = 0; nLevelIndex <= 9; nLevelIndex++) + { + sLevelIndex = IntToString(nLevelIndex); + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_level_" + sLevelIndex + "_event", JsonBool(FALSE)); + } + NuiSetBind(oPC, nToken, "btn_level_10_encouraged", JsonBool(TRUE)); + } + NuiSetBind(oPC, nToken, "btn_class_" + IntToString(nClass) + "_encouraged", JsonBool(TRUE)); + } + } + } + // Row 3 Items/Abilities/Skills/Spells + int nSpell, nMetaMagic, nDomain, nSubSpell, nSubSpellIndex; + int nSpellSlot, nCounter, nMax2daRow, nFeat; + string sSpellIcon, sSpellName, sMetaMagicText, sClassFeats, sSubSpellIndex; + object oItem; + json jQuickListArray = JsonArray(); + json jSpell; + json jSpell_Icon = JsonArray(); + json jSpell_Text = JsonArray(); + SetLocalJson(oAssociate, "JSPELL_ICON", jSpell_Icon); + SetLocalJson(oAssociate, "JSPELL_NAME", jSpell_Text); + json jMetaMagic_Text = JsonArray(); + // Item powers + if(nLevel == 11) + { + string sSlots; + // Cycle through all the creatures inventory items. + oItem = GetFirstItemInInventory(oAssociate); + while(oItem != OBJECT_INVALID) + { + if(GetIdentified(oItem)) + { + // Does the item need to be equiped to use its powers? + sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)); + if(sSlots == "0x00000") + { + jQuickListArray = ai_CheckItemAbilities(jQuickListArray, oAssociate, oItem, jSpell_Icon, jSpell_Text, FALSE); + jSpell_Icon = GetLocalJson(oAssociate, "JSPELL_ICON"); + jSpell_Text = GetLocalJson(oAssociate, "JSPELL_NAME"); + WriteTimestampedLogEntry("0i_menus, 3643, oAssociate: " + GetName(oAssociate) + + " jSpell_Text: " + JsonDump(jSpell_Text, 4)); + } + } + oItem = GetNextItemInInventory(oAssociate); + } + int nSlot; + // Cycle through all the creatures equiped items. + oItem = GetItemInSlot(nSlot, oAssociate); + while(nSlot < 11) + { + if(oItem != OBJECT_INVALID) + { + jQuickListArray = ai_CheckItemAbilities(jQuickListArray, oAssociate, oItem, jSpell_Icon, jSpell_Text, TRUE); + jSpell_Icon = GetLocalJson(oAssociate, "JSPELL_ICON"); + jSpell_Text = GetLocalJson(oAssociate, "JSPELL_NAME"); + } + oItem = GetItemInSlot(++nSlot, oAssociate); + } + oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oAssociate); + if(oItem != OBJECT_INVALID) + { + jQuickListArray = ai_CheckItemAbilities(jQuickListArray, oAssociate, oItem, jSpell_Icon, jSpell_Text, TRUE); + jSpell_Icon = GetLocalJson(oAssociate, "JSPELL_ICON"); + jSpell_Text = GetLocalJson(oAssociate, "JSPELL_NAME"); + } + DeleteLocalJson(oAssociate, "JSPELL_ICON"); + DeleteLocalJson(oAssociate, "JSPELL_NAME"); + } + // Special abilities and skills. + else if(nLevel == 10) + { + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClassIndex = GetClassByPosition(nIndex, oAssociate); + if(nClassIndex != CLASS_TYPE_INVALID) + { + nCounter = 0; + sClassFeats = Get2DAString("classes", "FeatsTable", nClassIndex); + nMax2daRow = Get2DARowCount(sClassFeats); + while(nCounter < nMax2daRow) + { + if(Get2DAString(sClassFeats, "OnMenu", nCounter) != "0") + { + nFeat = StringToInt(Get2DAString(sClassFeats, "FeatIndex", nCounter)); + if(GetHasFeat(nFeat, oAssociate, TRUE)) + { + // Check for subfeats. + nSpell = StringToInt(Get2DAString("feat", "SPELLID", nFeat)); + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell1", nSpell)); + //SendMessageToPC(oPC, "nFeat: " + IntToString(nFeat) + + // " nSpell: " + IntToString(nSpell) + + // " nSubSpell: " + IntToString(nSubSpell)); + if(nSubSpell) + { + for(nSubSpellIndex = 1; nSubSpellIndex <= 5; nSubSpellIndex++) + { + sSubSpellIndex = IntToString(nSubSpellIndex); + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell" + sSubSpellIndex, nSpell)); + //SendMessageToPC(oPC, " nSpell: " + IntToString(nSpell) + + // " nSubSpell: " + IntToString(nSubSpell)); + if(nSubSpell != 0) + { + sSpellIcon = Get2DAString("spells", "iConResRef", nSubSpell); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSubSpell))); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSubSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jSpell = JsonArrayInsert(jSpell, JsonInt(255)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nFeat)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + } + else if((nFeat < 71 || nFeat > 81)) + { + sSpellIcon = Get2DAString("feat", "ICON", nFeat); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jSpell = JsonArrayInsert(jSpell, JsonInt(255)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nFeat)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + } + nCounter++; + } + } + } + // Used in the execution script to get the special abilities. + //jData = JsonArrayInsert(jData, jQuickListArray); + } + else // Anything else is for spells. + { + // Search all memorized spells for the spell. + //SendMessageToPC(oPC, GetName(oAssociate) + " nClass: " + IntToString(nClass) + + // " nLevelSelected: " + IntToString(nLevel) + + // " nMemorizesSpells: " + Get2DAString("classes", "MemorizesSpells", nClass)); + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + int nMaxSlot = GetMemorizedSpellCountByLevel(oAssociate, nClass, nLevel); + while(nSpellSlot < nMaxSlot) + { + nSpell = GetMemorizedSpellId(oAssociate, nClass, nLevel, nSpellSlot); + if(nSpell != -1 && ai_SpellNotInList(nSpell, jQuickListArray)) + { + nMetaMagic = GetMemorizedSpellMetaMagic(oAssociate, nClass, nLevel, nSpellSlot); + nDomain = GetMemorizedSpellIsDomainSpell(oAssociate, nClass, nLevel, nSpellSlot); + // Check for subspells. + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell1", nSpell)); + if(nSubSpell) + { + for(nSubSpellIndex = 1; nSubSpellIndex < 6; nSubSpellIndex++) + { + sSubSpellIndex = IntToString(nSubSpellIndex); + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell" + sSubSpellIndex, nSpell)); + if(nSubSpell && ai_SpellNotInList(nSubSpell, jQuickListArray)) + { + sSpellIcon = Get2DAString("spells", "IconResRef", nSubSpell); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSubSpell))); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + jMetaMagic_Text = JsonArrayInsert(jMetaMagic_Text, JsonString(sMetaMagicText)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSubSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nMetaMagic)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nDomain)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + } + else + { + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + jMetaMagic_Text = JsonArrayInsert(jMetaMagic_Text, JsonString(sMetaMagicText)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nMetaMagic)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nDomain)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + //SendMessageToPC(oPC, "nSpell: " + IntToString(nSpell) + + // " sSpellIcon: " + sSpellIcon + + // " sSpellName: " + sSpellName+ + // " nMaxSlot: " + IntToString(nMaxSlot) + + // " nSpellSlot: " + IntToString(nSpellSlot)); + } + } + ++nSpellSlot; + } + } + // Non-memorized spells. + else + { + int nMaxSlot = GetKnownSpellCount(oAssociate, nClass, nLevel); + while(nSpellSlot < nMaxSlot) + { + nSpell = GetKnownSpellId(oAssociate, nClass, nLevel, nSpellSlot); + if(nSpell != -1)// && ai_SpellNotInList(nSpell, jQuickListArray)) + { + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel)); + jSpell = JsonArrayInsert(jSpell, JsonInt(255)); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + ++nSpellSlot; + } + } + } + NuiSetBind(oPC, nToken, "icon_spell", jSpell_Icon); + NuiSetBind(oPC, nToken, "text_spell", jSpell_Text); + NuiSetBind(oPC, nToken, "metamagic_text", jMetaMagic_Text); + jData = JsonArrayInsert(jData, jQuickListArray); + NuiSetUserData(oPC, nToken, jData); + // Row 4 Quick widget list label. + // Row 5 Quick widget List 1 + json jWidget = JsonArrayGet(jSpells, 2); + nIndex = 0; + while(nIndex < 10) + { + jSpell = JsonArrayGet(jWidget, nIndex); + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nClass == -1) // This is an Item. + { + string sBaseName; + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + int nBaseItemType = JsonGetInt(JsonArrayGet(jSpell, 3)); + int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4)); + if(nSpell == SPELL_HEALINGKIT) + { + sName = "Healer's Kit +" + IntToString(nIprpSubType); + sSpellIcon = "isk_heal"; + sBaseName = "Healer's Kit"; + } + else if(nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL) + { + sSpellIcon = Get2DAString("iprp_spells", "Icon", nIprpSubType); + sBaseName = "Scroll"; + } + else + { + if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) sBaseName = "Potion"; + else if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == FEAT_CRAFT_WAND) sBaseName = "Wand"; + else sBaseName = ai_StripColorCodes(GetName(GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + int nUses = ai_GetItemUses(oItem, nIprpSubType); + if(nUses) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(nUses == 999) sText = "Unlimited"; + else sText = IntToString(nUses); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")")); + } + } + else if(nFeat) // This is a feat. + { + sSpellIcon = ""; + if(nSpell) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + if(sSpellIcon == "" || sSpellIcon == "IR_USE") + { + sName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + sSpellIcon = Get2DAString("feat", "ICON", nFeat); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName)); + } + else // This is a spell. + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + nLevel = JsonGetInt(JsonArrayGet(jSpell, 2)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + } + } + else + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString("")); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + ++nIndex; + } + if(nIndex < 10) return; + // Row 6 Quick widget List2 + while(nIndex < 20) + { + jSpell = JsonArrayGet(jWidget, nIndex); + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nClass == -1) // This is an Item. + { + string sBaseName; + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + int nBaseItemType = JsonGetInt(JsonArrayGet(jSpell, 3)); + int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4)); + if(nSpell == SPELL_HEALINGKIT) + { + sName = "Healer's Kit +" + IntToString(nIprpSubType); + sSpellIcon = "isk_heal"; + sBaseName = "Healer's Kit"; + } + else if(nBaseItemType == BASE_ITEM_ENCHANTED_SCROLL || + nBaseItemType == BASE_ITEM_SCROLL || + nBaseItemType == BASE_ITEM_SPELLSCROLL) + { + sSpellIcon = Get2DAString("iprp_spells", "Icon", nIprpSubType); + sBaseName = "Scroll"; + } + else + { + if(nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) sBaseName = "Potion"; + else if(nBaseItemType == BASE_ITEM_ENCHANTED_WAND || + nBaseItemType == BASE_ITEM_MAGICWAND || + nBaseItemType == FEAT_CRAFT_WAND) sBaseName = "Wand"; + else sBaseName = ai_StripColorCodes(GetName(GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + int nUses = ai_GetItemUses(oItem, nIprpSubType); + if(nUses) + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE)); + if(nUses == 999) sText = "Unlimited"; + else sText = IntToString(nUses); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")")); + } + } + else if(nFeat) // This is a feat. + { + sSpellIcon = ""; + if(nSpell) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + } + if(sSpellIcon == "" || sSpellIcon == "IR_USE") + { + sName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + sSpellIcon = Get2DAString("feat", "ICON", nFeat); + } + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName)); + } + else // This is a spell. + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + nLevel = JsonGetInt(JsonArrayGet(jSpell, 2)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")")); + sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + } + } + else + { + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString("")); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE)); + } + ++nIndex; + } +} +void ai_CreateSpellMemorizationNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jRow = JsonArray(); + // Row 1 Classes************************************************************ 414 / 73 + int nClass, bCaster, nIndex; + string sIndex, sClassIcon, sLevelIcon; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass != CLASS_TYPE_INVALID) + { + if(StringToInt(Get2DAString("classes", "MemorizesSpells", nClass))) + { + // This saves the class position in the button id so we can get it later. + sIndex = IntToString(nIndex); + sClassIcon = Get2DAString("classes", "Icon", nClass); + jRow = CreateButtonImage(jRow, sClassIcon, "btn_class_" + sIndex, 35.0f, 35.0f, 0.0, "btn_class_" + sIndex + "_tooltip"); + } + } + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Levels) ********************************************************** 414 / 116 + jRow = JsonArray(); + for(nIndex = 0; nIndex <= 9; nIndex++) + { + // This saves the level in the button id so we can get it later. + sIndex = IntToString(nIndex); + jRow = CreateButtonImage(jRow, "", "btn_level_" + sIndex, 35.0f, 35.0f, 0.0, "btn_level_" + sIndex + "_tooltip"); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Spell List)******************************************************* 414 / 398 + json jButton = JsonArray(); + jButton = NuiButton(NuiBind("text_spell")); + jButton = NuiId(jButton, "btn_text_spell"); + json jRectangle = NuiRect(4.0, 4.0, 27.0, 27.0); + json jDrawList = JsonArrayInsert(JsonArray(), NuiDrawListImage(JsonBool(TRUE), NuiBind("icon_spell"), jRectangle, JsonInt(NUI_ASPECT_FILL), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_MIDDLE))); + //jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + //json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_text")); + //jDrawList = JsonArrayInsert(jDrawList, jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + json jListTemplate = JsonArrayInsert(JsonArray(), NuiListTemplateCell(jButton, 275.0, FALSE)); + json jInfo = NuiButtonImage(JsonString("gui_cg_qstn_mark")); + jInfo = NuiId(jInfo, "btn_info_spell"); + jListTemplate = JsonArrayInsert(jListTemplate, NuiListTemplateCell(jInfo, 35.0, FALSE)); + jRow = JsonArrayInsert(JsonArray(), NuiHeight(NuiList(jListTemplate, NuiBind("icon_spell"), 35.0), 282.0)); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (Widget Label)***************************************************** 414 / 426 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + CreateLabel(jRow, "Memorized Spell List", "lbl_spell_list", 150.0, 20.0, 0, 0, 0.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 (Memorize slots)*************************************************** 414 / 469 + // Get the class and level selected from the database. + int nClassSelected, nLevelSelected; + json jSpells; + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + // Temporary fix for error! :/ + if(JsonGetLength(jAIData) == 0) + { + ai_CheckAssociateData(oPC, oAssociate, sAssociateType, TRUE); + jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + } + if(JsonGetLength(jAIData) == 9) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(0)); + jAIData = JsonArrayInsert(jAIData, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + else + { + jSpells = JsonArrayGet(jAIData, 10); + if(JsonGetType(jSpells) == JSON_TYPE_NULL) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(0)); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + else + { + nClassSelected = JsonGetInt(JsonArrayGet(jSpells, 0)); + nLevelSelected = JsonGetInt(JsonArrayGet(jSpells, 1)); + } + } + // If we left the Quick Use widget on Special Abilities (10) or Items (11) goto level 0 + if(nLevelSelected == 10 || nLevelSelected == 11) + { + nLevelSelected = 0; + jSpells = JsonArraySet(jSpells, 1, JsonInt(0)); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + if(nClassSelected < 1 || nClassSelected > AI_MAX_CLASSES_PER_CHARACTER) nClassSelected = 1; + nClass = GetClassByPosition(nClassSelected, oAssociate); + int nMaxMemorizationSlots = GetMemorizedSpellCountByLevel(oAssociate, nClass, nLevelSelected); + jRow = JsonArray(); + for(nIndex = 0; nIndex < nMaxMemorizationSlots; nIndex++) + { + // This saves the index location of the spell in the list. + sIndex = IntToString(nIndex); + json jButton = NuiButtonImage(NuiBind("btn_memorized_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_memorized_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_memorized_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_memorized_" + sIndex + "_tooltip")); + //json jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + //json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + //jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + //jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_SPELL_MEMORIZE_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + string sText, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_SPELL_MEMORIZE_NUI, sName + " Spell Memorization Menu", + fX, fY, 375.0, 504.0 + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Set the Layout of the window. + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Row 1 & 2 Class & Level + int nSpellLevel, nIndexLevel, nMaxSpellLevel; + string sClass, sLevel, sLevelImage, sIndexLevel; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass != CLASS_TYPE_INVALID) + { + bCaster = StringToInt(Get2DAString("classes", "SpellCaster", nClass)); + if(bCaster) + { + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_tooltip", JsonString(" " + sClass)); + if(nClassSelected == nIndex) + { + int nClassLevel = GetLevelByClass(nClass, oAssociate); + string sSpellsGained = Get2DAString("classes", "SpellGainTable", nClass); + int nMaxSpellLevel = StringToInt(Get2DAString(sSpellsGained, "NumSpellLevels", nClassLevel - 1)); + for(nIndexLevel = 0; nIndexLevel <= 9; nIndexLevel++) + { + sIndexLevel = IntToString(nIndexLevel); + if(nIndexLevel < nMaxSpellLevel) + { + if(nIndexLevel == 0) sLevelImage = "ir_cantrips"; + else if(nIndexLevel < 7)sLevelImage = "ir_level" + sIndexLevel; + else sLevelImage = "ir_level789"; + if(nIndexLevel == 0) sLevel = " Cantrips"; + else if(nIndexLevel == 1) sLevel = " First level"; + else if(nIndexLevel == 2) sLevel = " Second level"; + else if(nIndexLevel == 3) sLevel = " Third level"; + else if(nIndexLevel == 4) sLevel = " Fourth level"; + else if(nIndexLevel == 5) sLevel = " Fifth level"; + else if(nIndexLevel == 6) sLevel = " Sixth level"; + else if(nIndexLevel == 7) sLevel = " Seventh level"; + else if(nIndexLevel == 8) sLevel = " Eighth level"; + else if(nIndexLevel == 9) sLevel = " Ninth level"; + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_tooltip", JsonString(" " + sLevel)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_image", JsonString(sLevelImage)); + } + else + { + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(FALSE)); + } + } + NuiSetBind(oPC, nToken, "btn_level_" + IntToString(nLevelSelected) + "_encouraged", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_class_" + IntToString(nClassSelected) + "_encouraged", JsonBool(TRUE)); + } + } + } + } + // Row 3 Spells + int nSpellSlot, nSpell, nMetamagic; + json jSpell; + json jWidget = JsonArrayGet(jSpells, 2); + nClass = GetClassByPosition(nClassSelected, oAssociate); + string sSpellIcon, sSpellName, sMetaMagicText; + json jSpellArray = JsonArray(); + json jSpell_Icon = JsonArray(); + json jSpell_Text = JsonArray(); + json jMetaMagic_Text = JsonArray(); + // List the spells they know from their spellbook. + if(Get2DAString("classes", "SpellbookRestricted", nClass) == "1") + { + int nMaxSpells = GetKnownSpellCount(oAssociate, nClass, nLevelSelected); + //WriteTimestampedLogEntry("Maxspells: " + IntToString(nMaxSpells) + + // " nClass: " + IntToString(nClass) + + // " nLevelSelected: " + IntToString(nLevelSelected)); + while(nSpellSlot < nMaxSpells) + { + nSpell = GetKnownSpellId(oAssociate, nClass, nLevelSelected, nSpellSlot); + if(nSpell != -1) + { + jSpellArray = JsonArrayInsert(jSpellArray, JsonInt(nSpell)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + //SendMessageToPC(oPC, "SpellBook: nSpell: " + IntToString(nSpell) + + // " sSpellIcon: " + sSpellIcon + + // " sSpellName: " + sSpellName+ + // " nMaxSpells: " + IntToString(nMaxSpells) + + // " nSpellSlot: " + IntToString(nSpellSlot)); + //sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nClass, nLevelSelected, nSpellSlot); + //jMetaMagic_Text = JsonArrayInsert(jMetaMagic_Text, JsonString(sMetaMagicText)); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + } + ++nSpellSlot; + } + } + // List the spells from the spells.2da file (they get to choose from them all!). + else + { + string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass); + int nMaxSpells = Get2DARowCount("spells"); + while(nSpell < nMaxSpells) + { + sLevel = Get2DAString("spells", sSpellTableColumn, nSpell); + if(sLevel != "") + { + if(StringToInt(sLevel) == nLevelSelected) + { + jSpellArray = JsonArrayInsert(jSpellArray, JsonInt(nSpell)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + } + } + ++nSpell; + } + } + jData = JsonArrayInsert(jData, jSpellArray); + NuiSetUserData(oPC, nToken, jData); + NuiSetBind(oPC, nToken, "icon_spell", jSpell_Icon); + NuiSetBind(oPC, nToken, "text_spell", jSpell_Text); + NuiSetBind(oPC, nToken, "metamagic_text", jMetaMagic_Text); + // Row 4 Spell memorized list label. + // Row 5 Spell memorized List + int nMetaMagic, nDomain; + nIndex = 0; + while(nIndex < nMaxMemorizationSlots) + { + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_event", JsonBool(TRUE)); + if(GetMemorizedSpellId(oAssociate, nClass, nLevelSelected, nIndex) > -1) + { + nSpell = GetMemorizedSpellId(oAssociate, nClass, nLevelSelected, nIndex); + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + //nMetaMagic = 255; + //nDomain = 0; + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevelSelected) + ")")); + //sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, -1, -1, -1, nMetaMagic, nDomain); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + } + else + { + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString("")); + NuiSetBind(oPC, nToken, "btn_memorized_" + sIndex + "_event", JsonBool(FALSE)); + } + ++nIndex; + } +} +void ai_CreateSpellKnownNUI(object oPC, object oAssociate) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jRow = JsonArray(); + // Row 1 Classes************************************************************ 414 / 73 + int nClass, bCaster, nIndex; + string sIndex, sClassIcon, sLevelIcon; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass != CLASS_TYPE_INVALID) + { + if(StringToInt(Get2DAString("classes", "SpellbookRestricted", nClass))) + { + // This saves the class position in the button id so we can get it later. + sIndex = IntToString(nIndex); + sClassIcon = Get2DAString("classes", "Icon", nClass); + jRow = CreateButtonImage(jRow, sClassIcon, "btn_class_" + sIndex, 35.0f, 35.0f, 0.0, "btn_class_" + sIndex + "_tooltip"); + } + } + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Levels) ********************************************************** 414 / 116 + jRow = JsonArray(); + for(nIndex = 0; nIndex <= 9; nIndex++) + { + // This saves the level in the button id so we can get it later. + sIndex = IntToString(nIndex); + jRow = CreateButtonImage(jRow, "", "btn_level_" + sIndex, 35.0f, 35.0f, 0.0, "btn_level_" + sIndex + "_tooltip"); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Spell List)******************************************************* 414 / 398 + json jButton = JsonArray(); + jButton = NuiButton(NuiBind("text_spell")); + jButton = NuiId(jButton, "btn_text_spell"); + json jRectangle = NuiRect(4.0, 4.0, 27.0, 27.0); + json jDrawList = JsonArrayInsert(JsonArray(), NuiDrawListImage(JsonBool(TRUE), NuiBind("icon_spell"), jRectangle, JsonInt(NUI_ASPECT_FILL), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_MIDDLE))); + //jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + //json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_text")); + //jDrawList = JsonArrayInsert(jDrawList, jMetaMagic); + jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + json jListTemplate = JsonArrayInsert(JsonArray(), NuiListTemplateCell(jButton, 275.0, FALSE)); + json jInfo = NuiButtonImage(JsonString("gui_cg_qstn_mark")); + jInfo = NuiId(jInfo, "btn_info_spell"); + jListTemplate = JsonArrayInsert(jListTemplate, NuiListTemplateCell(jInfo, 35.0, FALSE)); + jRow = JsonArrayInsert(JsonArray(), NuiHeight(NuiList(jListTemplate, NuiBind("icon_spell"), 35.0), 282.0)); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (Widget Label)***************************************************** 414 / 426 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + CreateLabel(jRow, "Known Spell List", "lbl_spell_list", 150.0, 20.0, 0, 0, 0.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 (Memorize slots)*************************************************** 414 / 469 + // Get the class and level selected from the database. + int nClassSelected, nLevelSelected; + json jSpells; + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + // Temporary fix for error! :/ + if(JsonGetLength(jAIData) == 0) + { + ai_CheckAssociateData(oPC, oAssociate, sAssociateType, TRUE); + jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + } + if(JsonGetLength(jAIData) == 9) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(0)); + jAIData = JsonArrayInsert(jAIData, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + else + { + jSpells = JsonArrayGet(jAIData, 10); + if(JsonGetType(jSpells) == JSON_TYPE_NULL) + { + jSpells = JsonArray(); + jSpells = JsonArrayInsert(jSpells, JsonInt(1)); + jSpells = JsonArrayInsert(jSpells, JsonInt(0)); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + else + { + nClassSelected = JsonGetInt(JsonArrayGet(jSpells, 0)); + nLevelSelected = JsonGetInt(JsonArrayGet(jSpells, 1)); + } + } + // If we left the Quick Use widget on Special Abilities (10) or Items (11) goto level 0 + if(nLevelSelected == 10 || nLevelSelected == 11) + { + nLevelSelected = 0; + jSpells = JsonArraySet(jSpells, 1, JsonInt(0)); + jAIData = JsonArraySet(jAIData, 10, jSpells); + ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData); + } + if(nClassSelected < 1 || nClassSelected > AI_MAX_CLASSES_PER_CHARACTER) nClassSelected = 1; + nClass = GetClassByPosition(nClassSelected, oAssociate); + jRow = JsonArray(); + for(nIndex = 0; nIndex < 10; nIndex++) + { + // This saves the index location of the spell in the list. + sIndex = IntToString(nIndex); + json jButton = NuiButtonImage(NuiBind("btn_known_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_known_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_known_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_known_" + sIndex + "_tooltip")); + //json jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + //json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + //jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + //jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Do the second row. + jRow = JsonArray(); + for(nIndex = 10; nIndex < 20; nIndex++) + { + // This saves the index location of the spell in the list. + sIndex = IntToString(nIndex); + json jButton = NuiButtonImage(NuiBind("btn_known_" + sIndex + "_image")); + jButton = NuiEnabled(jButton, NuiBind("btn_known_" + sIndex + "_event")); + jButton = NuiId(jButton, "btn_known_" + sIndex); + jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind("btn_known_" + sIndex + "_tooltip")); + //json jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0); + //json jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text")); + //jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic); + //jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList); + jRow = JsonArrayInsert(jRow, jButton); + } + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + float fX, fY; + json jLocations = ai_GetAssociateDbJson(oPC, sAssociateType, "locations"); + jLocations = JsonObjectGet(jLocations, sAssociateType + AI_SPELL_KNOWN_NUI); + if(JsonGetType(jLocations) == JSON_TYPE_NULL) { fX = -1.0; fY = -1.0; } + else + { + fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + } + string sText, sName = GetName(oAssociate); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPC, jLayout, sAssociateType + AI_SPELL_KNOWN_NUI, sName + " Spell Known Menu", + fX, fY, 375.0, 539.0 + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + // Set the Layout of the window. + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oAssociate))); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Row 1 & 2 Class & Level + int nSpellLevel, nIndexLevel, nMaxSpellLevel, nClassLevel; + string sClass, sLevel, sLevelImage, sIndexLevel, sSpellsGained; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass != CLASS_TYPE_INVALID) + { + bCaster = StringToInt(Get2DAString("classes", "SpellbookRestricted", nClass)); + if(bCaster) + { + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_class_" + sIndex + "_tooltip", JsonString(" " + sClass)); + if(nClassSelected == nIndex) + { + nClassLevel = GetLevelByClass(nClass, oAssociate); + sSpellsGained = Get2DAString("classes", "SpellGainTable", nClass); + nMaxSpellLevel = StringToInt(Get2DAString(sSpellsGained, "NumSpellLevels", nClassLevel - 1)); + for(nIndexLevel = 0; nIndexLevel <= 9; nIndexLevel++) + { + sIndexLevel = IntToString(nIndexLevel); + if(nIndexLevel < nMaxSpellLevel) + { + if(nIndexLevel == 0) sLevelImage = "ir_cantrips"; + else if(nIndexLevel < 7)sLevelImage = "ir_level" + sIndexLevel; + else sLevelImage = "ir_level789"; + if(nIndexLevel == 0) sLevel = " Cantrips"; + else if(nIndexLevel == 1) sLevel = " First level"; + else if(nIndexLevel == 2) sLevel = " Second level"; + else if(nIndexLevel == 3) sLevel = " Third level"; + else if(nIndexLevel == 4) sLevel = " Fourth level"; + else if(nIndexLevel == 5) sLevel = " Fifth level"; + else if(nIndexLevel == 6) sLevel = " Sixth level"; + else if(nIndexLevel == 7) sLevel = " Seventh level"; + else if(nIndexLevel == 8) sLevel = " Eighth level"; + else if(nIndexLevel == 9) sLevel = " Ninth level"; + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_tooltip", JsonString(" " + sLevel)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_image", JsonString(sLevelImage)); + } + else + { + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_level_" + sIndexLevel + "_event", JsonBool(FALSE)); + } + } + NuiSetBind(oPC, nToken, "btn_level_" + IntToString(nLevelSelected) + "_encouraged", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_class_" + IntToString(nClassSelected) + "_encouraged", JsonBool(TRUE)); + } + } + } + } + // Row 3 Spells + int nSpellSlot, nSpell, nMetamagic; + json jSpell; + json jWidget = JsonArrayGet(jSpells, 2); + nClass = GetClassByPosition(nClassSelected, oAssociate); + string sSpellIcon, sSpellName, sMetaMagicText; + json jSpellArray = JsonArray(); + json jSpell_Icon = JsonArray(); + json jSpell_Text = JsonArray(); + json jMetaMagic_Text = JsonArray(); + // List the spells from the spells.2da file (they get to choose from them all!). + string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass); + int nMaxSpells = Get2DARowCount("spells"); + while(nSpell < nMaxSpells) + { + sLevel = Get2DAString("spells", sSpellTableColumn, nSpell); + if(sLevel != "") + { + if(StringToInt(sLevel) == nLevelSelected) + { + jSpellArray = JsonArrayInsert(jSpellArray, JsonInt(nSpell)); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon)); + jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName)); + } + } + ++nSpell; + } + jData = JsonArrayInsert(jData, jSpellArray); + NuiSetUserData(oPC, nToken, jData); + NuiSetBind(oPC, nToken, "icon_spell", jSpell_Icon); + NuiSetBind(oPC, nToken, "text_spell", jSpell_Text); + NuiSetBind(oPC, nToken, "metamagic_text", jMetaMagic_Text); + // Row 4 Spell known list label. + // Row 5 Spell known List + int nMetaMagic, nDomain, nMaxKnownSlots; + json jClassList = GetLocalJson(oAssociate, AI_CLASS_LIST_JSON); + if(JsonGetType(jClassList) == JSON_TYPE_NULL) + { + jClassList = ObjectToJson(oAssociate); + jClassList = GffGetList(jClassList, "ClassList"); + SetLocalJson(oAssociate, AI_CLASS_LIST_JSON, jClassList); + } + // Get the correct class array. + nIndex = 0; + json jClass = JsonArrayGet(jClassList, nIndex); + while(JsonGetInt(GffGetInt(jClass, "Class")) != nClass) + { + jClass = JsonArrayGet(jClassList, ++nIndex); + } + json jKnownList = GffGetList(jClass, "KnownList" + IntToString(nLevelSelected)); + string sSpellKnownTable = Get2DAString("classes", "SpellKnownTable", nClass); + if(sSpellKnownTable != "") nMaxKnownSlots = StringToInt(Get2DAString(sSpellKnownTable, "SpellLevel" + IntToString(nLevelSelected), nClassLevel - 1)); + else nMaxKnownSlots = 20; + nIndex = 0; + while(nIndex < 20) + { + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_event", JsonBool(TRUE)); + if(nIndex < nMaxKnownSlots) + { + jSpell = JsonArrayGet(jKnownList, nIndex); + if(JsonGetType(jSpell) == JSON_TYPE_NULL) + { + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_tooltip", JsonString(" Empty known spell slot")); + } + else + { + nSpell = JsonGetInt(GffGetWord(jSpell, "Spell")); + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + //nMetaMagic = 255; + //nDomain = 0; + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevelSelected) + ")")); + //sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, -1, -1, -1, nMetaMagic, nDomain); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText)); + } + } + else + { + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_image", JsonString("ctl_cg_btn_splvl")); + //NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString("")); + NuiSetBind(oPC, nToken, "btn_known_" + sIndex + "_event", JsonBool(FALSE)); + } + ++nIndex; + } +} +void ai_CreateDescriptionNUI(object oPC, json jSpell, int nSpell = 0) +{ + // Row 1 ******************************************************************* 500 / 469 + json jRow = CreateImage(JsonArray(), "", "spell_icon", NUI_ASPECT_FIT, NUI_HALIGN_CENTER, NUI_VALIGN_MIDDLE, 40.0, 40.0); + jRow = CreateTextBox(jRow, "spell_text", 380.0, 400.0, FALSE, NUI_SCROLLBARS_Y); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 1 ******************************************************************* 500 / 522 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "OK", "btn_ok", 150.0f, 45.0f); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sName, sIcon, sDescription; + int nFeat, nDescription; + int nClass; + if(nSpell) nClass = 0; + else + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + } + if(nClass == -1) + { + if(nSpell == SPELL_HEALINGKIT) + { + sName = "Healer's Kit"; + sIcon = "isk_heal"; + sDescription = GetStringByStrRef(1720); + } + else + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sIcon = Get2DAString("spells", "IconResRef", nSpell); + nDescription = StringToInt(Get2DAString("spells", "SpellDesc", nSpell)); + if(nDescription) sDescription = GetStringByStrRef(nDescription); + else + { + object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + sDescription = GetDescription(oItem); + } + } + } + else + { + nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nFeat) + { + if(nSpell) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sIcon = Get2DAString("spells", "IconResRef", nSpell); + } + else + { + sName = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))); + sIcon = Get2DAString("feat", "ICON", nFeat); + } + sDescription = GetStringByStrRef(StringToInt(Get2DAString("feat", "DESCRIPTION", nFeat))); + } + else + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sIcon = Get2DAString("spells", "IconResRef", nSpell); + nDescription = StringToInt(Get2DAString("spells", "SpellDesc", nSpell)); + if(nDescription) sDescription = GetStringByStrRef(nDescription); + else + { + object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + sDescription = GetDescription(oItem); + } + } + } + int nToken = SetWindow(oPC, jLayout, AI_SPELL_DESCRIPTION_NUI, sName, + -1.0, -1.0, 460.0f, 537.0 + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui"); + json jData = JsonArray(); + jData = JsonArrayInsert(jData, JsonString(ObjectToString(oPC))); + NuiSetUserData(oPC, nToken, jData); + // Row 1 + NuiSetBind(oPC, nToken, "spell_icon_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "spell_icon_image", JsonString(sIcon)); + NuiSetBind(oPC, nToken, "spell_text_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "spell_text", JsonString(sDescription)); + // Row 2 + NuiSetBind(oPC, nToken, "btn_ok_event", JsonBool(TRUE)); +} + diff --git a/src/module/nss/0i_menus_dm.nss b/src/module/nss/0i_menus_dm.nss new file mode 100644 index 0000000..a2a2cfc --- /dev/null +++ b/src/module/nss/0i_menus_dm.nss @@ -0,0 +1,1386 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_menus_dm +//////////////////////////////////////////////////////////////////////////////// + Include script for handling NUI menus for DMs. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "0i_associates" +string ai_GetRandomDMTip() +{ + int nRoll = Random(44); + return Get2DAString("ai_messages", "Text", nRoll); +} +void ai_SetDMWidgetButton(object oPlayer, int nButton, int bOn = TRUE) +{ + int nWidgetButtons = GetLocalInt(oPlayer, sDMWidgetButtonVarname); + string sName = ai_RemoveIllegalCharacters(GetName(oPlayer)); + json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE); + if(nWidgetButtons == 0) nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0)); + if(bOn) nWidgetButtons = nWidgetButtons | nButton; + else nWidgetButtons = nWidgetButtons & ~nButton; + SetLocalInt(oPlayer, sDMWidgetButtonVarname, nWidgetButtons); + jButtons = JsonArraySet(jButtons, 0, JsonInt(nWidgetButtons)); + ai_SetCampaignDbJson("buttons", jButtons, sName, AI_DM_TABLE); +} +int ai_GetDMWidgetButton(object oPlayer, int nButton) +{ + int nWidgetButtons = GetLocalInt(oPlayer, sDMWidgetButtonVarname); + if(nWidgetButtons == 0) + { + string sName = ai_RemoveIllegalCharacters(GetName(oPlayer)); + json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE); + nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0)); + } + return nWidgetButtons & nButton; +} +void ai_CreateDMWidgetNUI(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int bAIWidgetLock = ai_GetDMWidgetButton(oPC, BTN_DM_WIDGET_LOCK); + int bCmdGroup1 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP1); + int bCmdGroup2 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP2); + int bCmdGroup3 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP3); + int bCmdGroup4 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP4); + int bCmdGroup5 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP5); + int bCmdGroup6 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP6); + int bCmdCamera = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_CAMERA); + int bCmdInventory = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_INVENTORY); + // Get which buttons are activated. + float fHeight = 92.0f; + if(bAIWidgetLock) fHeight = 59.0f; + float fButtons, fWidth = 86.0f; + // ************************************************************************* Width / Height + // Row 1 (buttons)********************************************************** + // Setup the main associate button to use their portrait. + json jButton = NuiEnabled(NuiId (NuiButtonImage(NuiBind("btn_open_main_image")), "btn_open_main"), NuiBind("btn_open_main_event")); + jButton = NuiWidth(jButton, 35.0); + jButton = NuiHeight(jButton, 35.0); + jButton = NuiMargin(jButton, 0.0); + jButton = NuiTooltip(jButton, NuiBind ("btn_open_main_tooltip")); + jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 32.0, 35.0)); + json jRow = JsonArrayInsert(JsonArray(), jButton); + if(bCmdGroup1) + { + jRow = CreateButtonImage(jRow, "ir_level1", "btn_cmd_group1", 35.0f, 35.0f, 0.0, "btn_cmd_group1_tooltip"); + fButtons += 1.0; + } + if(bCmdGroup2) + { + jRow = CreateButtonImage(jRow, "ir_level2", "btn_cmd_group2", 35.0f, 35.0f, 0.0, "btn_cmd_group2_tooltip"); + fButtons += 1.0; + } + if(bCmdGroup3) + { + jRow = CreateButtonImage(jRow, "ir_level3", "btn_cmd_group3", 35.0f, 35.0f, 0.0, "btn_cmd_group3_tooltip"); + fButtons += 1.0; + } + if(bCmdGroup4) + { + jRow = CreateButtonImage(jRow, "ir_level4", "btn_cmd_group4", 35.0f, 35.0f, 0.0, "btn_cmd_group4_tooltip"); + fButtons += 1.0; + } + if(bCmdGroup5) + { + jRow = CreateButtonImage(jRow, "ir_level5", "btn_cmd_group5", 35.0f, 35.0f, 0.0, "btn_cmd_group5_tooltip"); + fButtons += 1.0; + } + if(bCmdGroup6) + { + jRow = CreateButtonImage(jRow, "ir_level6", "btn_cmd_group6", 35.0f, 35.0f, 0.0, "btn_cmd_group6_tooltip"); + fButtons += 1.0; + } + if(bCmdCamera) + { + jRow = CreateButtonImage(jRow, "ir_examine", "btn_camera", 35.0f, 35.0f, 0.0, "btn_camera_tooltip"); + fButtons += 1.0; + } + if(bCmdInventory) + { + jRow = CreateButtonImage(jRow, "ir_pickup", "btn_inventory", 35.0f, 35.0f, 0.0, "btn_inventory_tooltip"); + fButtons += 1.0; + } + // Plug in buttons ********************************************************* + int nIndex, bWidget; + string sButton, sIcon; + json jPlugins = ai_UpdatePluginsForDM(oPC); + json jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bWidget) + { + sIcon = JsonGetString(JsonArrayGet(jPlugin, 3)); + sButton = IntToString(nIndex); + jRow = CreateButtonImage(jRow, sIcon, "btn_exe_plugin_" + sButton, 35.0f, 35.0f, 0.0, "btn_exe_plugin_" + sButton + "_tooltip"); + fButtons += 1.0; + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + if(fButtons > 1.0f) fWidth = fWidth + ((fButtons - 1.0) * 39.0f); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Get the window location to restore it from the database. + string sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + jLocations = JsonObjectGet(jLocations, "dm" + AI_WIDGET_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + if(bAIWidgetLock) + { + fX = fX + 4.0f; + fY = fY + 37.0f; + } + // Set the layout of the window. + json jLayout = NuiCol(jCol); + int nToken; + string sHeal, sText, sRange; + string sDisplayName = GetName(oPC); + if(GetStringRight(sDisplayName, 1) == "s") sDisplayName = sDisplayName + "'"; + else sDisplayName = sDisplayName + "'s"; + if(bAIWidgetLock) nToken = SetWindow(oPC, jLayout, "dm" + AI_WIDGET_NUI, sDisplayName + " Widget", fX, fY, fWidth + 8.0f, fHeight, FALSE, FALSE, FALSE, TRUE, FALSE, "0e_nui_dm"); + else nToken = SetWindow(oPC, jLayout, "dm" + AI_WIDGET_NUI, sDisplayName + " Widget", fX, fY, fWidth + 12.0f, fHeight, FALSE, FALSE, FALSE, TRUE, TRUE, "0e_nui_dm"); + // Set event watches for window inspector and save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set the buttons to show events. + NuiSetBind(oPC, nToken, "btn_open_main_image", JsonString(GetPortraitResRef(oPC) + "s")); + NuiSetBind(oPC, nToken, "btn_open_main_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_open_main_tooltip", JsonString(" " + sDisplayName + " widget menu")); + string sUUID, sText2, sSpeed; + string sAction = " (Left Action/Right Add)"; + if(bCmdGroup1) + { + NuiSetBind(oPC, nToken, "btn_cmd_group1_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP1"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 1"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group1_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdGroup2) + { + NuiSetBind(oPC, nToken, "btn_cmd_group2_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP2"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 2"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group2_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdGroup3) + { + NuiSetBind(oPC, nToken, "btn_cmd_group3_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP3"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 3"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group3_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdGroup4) + { + NuiSetBind(oPC, nToken, "btn_cmd_group4_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP4"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 4"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group4_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdGroup5) + { + NuiSetBind(oPC, nToken, "btn_cmd_group5_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP5"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 5"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group5_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdGroup6) + { + NuiSetBind(oPC, nToken, "btn_cmd_group6_event", JsonBool(TRUE)); + json jGroup = GetLocalJson(oPC, "DM_GROUP6"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 6"; sText2 = sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group6_tooltip", JsonString(" " + sText + sText2)); + } + if(bCmdCamera) + { + NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString(" Select new object to have the camera view.")); + } + if(bCmdInventory) + { + NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString(" Open selected creatures inventory.")); + } + /*if(bSearch) + { + NuiSetBind(oPC, nToken, "btn_search_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH)) sText = " Search On"; + else sText = " Search Off"; + NuiSetBind(oPC, nToken, "btn_search_tooltip", JsonString(sText)); + } + if(bStealth) + { + NuiSetBind(oPC, nToken, "btn_stealth_event", JsonBool(TRUE)); + if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH)) sText = " Stealth On"; + else sText = " Stealth Off"; + NuiSetBind(oPC, nToken, "btn_stealth_tooltip", JsonString(sText)); + } */ + nIndex = 0; + string sScript; + jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + if(bWidget) + { + sButton = IntToString(nIndex); + sScript = JsonGetString(JsonArrayGet(jPlugin, 0)); + if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "") + { + sText = " " + sScript + " not found by ResMan!"; + } + else sName = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_exe_plugin_" + sButton + "_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_exe_plugin_" + sButton + "_tooltip", JsonString(sName)); + } + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } +} +void ai_CreateDMOptionsNUI(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand (2.0, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + int nMonsterAI = (ResManGetAliasFor("ai_default", RESTYPE_NCS) != ""); + int nAssociateAI = (ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != ""); + string sText = " [Single player]"; + if(AI_SERVER) sText = " [Server]"; + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, PHILOS_VERSION + sText, "lbl_version ", 510.0f, 20.0f, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 101 + jRow = CreateLabel(JsonArray(), "", "lbl_ai_info", 510.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 500 / 129 + jRow = CreateButton(JsonArray(), "Plugin Manager", "btn_plugin_manager", 160.0f, 20.0f, -1.0, "btn_plugin_manager_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Widget Manager", "btn_widget_manager", 160.0f, 20.0f, -1.0, "btn_widget_manager_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 500 / 157 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "SERVER RULES", "lbl_ai_rules", 100.0f, 20.0f, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 112.0; + // Row 5 ******************************************************************* 500 / --- (28) + // Make the AI options a Group. + json jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_max_henchman", 2, FALSE, 30.0f, 20.0f, "txt_max_henchman_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "Max number of henchmen that is allowed in your party.", "lbl_max_hench", 416.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_max_henchman_tooltip"); + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_xp_scale", 3, FALSE, 40.0f, 20.0f, "txt_xp_scale_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "Modules experience scale.", "lbl_xp_scale", 175.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_xp_scale_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " scale to party.", "chbx_party_scale", 130.0, 20.0, "chbx_party_scale_tooltip"); + jGroupRow = CreateButton(jGroupRow, "Default", "btn_default_xp", 70.0f, 20.0f, -1.0, "btn_default_xp_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 112.0; + if(nMonsterAI || nAssociateAI) + { + jGroupRow = CreateCheckBox(JsonArray(), " Creatures will use advanced combat movement.", "chbx_advanced_movement", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Use item level restrictions for creatures [Default is off].", "chbx_ilr", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Creatures can use the skill Use Magic Device.", "chbx_umd", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Creatures can use Healing kits.", "chbx_use_healingkits", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Moral checks, wounded creatures may flee during combat.", "chbx_moral", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), " Spells the AI will not use:", "lbl_restrict_spells", 190.0, 20.0, NUI_HALIGN_LEFT); + jGroupRow = CreateCheckBox(jGroupRow, " Darkness", "chbx_darkness", 90.0, 20.0, "chbx_darkness_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " Dispels", "chbx_dispels", 90.0, 20.0, "chbx_dispels_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, " Time Stop", "chbx_timestop", 90.0, 20.0, "chbx_timestop_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 168.0; + } + if(nMonsterAI) + { + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_ai_difficulty", 3, FALSE, 40.0f, 20.0f, "txt_ai_difficulty_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "% chance monsters will attack the weakest target.", "lbl_ai_difficulty", 406.0f, 20.0f, NUI_HALIGN_LEFT, 0, -1.0, "txt_ai_difficulty_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_perception_distance", 2, FALSE, 35.0f, 20.0f, "txt_perception_distance_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "meters is the distance a monster can respond to allies.", "lbl_perception_distance", 411.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "txt_perception_distance_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can prebuff before combat starts.", "chbx_buff_monsters", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can use summons before combat starts.", "chbx_buff_summons", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can use tactics (ambush, defensive, flanker, etc).", "chbx_ambush_monsters", 450.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "Add ", "lbl_inc_enc", 30.0, 20.0, NUI_HALIGN_LEFT, 0, -1.0); + jGroupRow = CreateTextEditBox(jGroupRow, "sPlaceHolder", "txt_inc_enc", 4, FALSE, 55.0f, 20.0f, "txt_inc_enc_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "monsters per spawned encounter monster.", "lbl_inc_enc", 357.0, 20.0, NUI_HALIGN_LEFT, NUI_VALIGN_MIDDLE, 0.0, "txt_inc_enc_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_inc_hp", 3, FALSE, 40.0f, 20.0f, "txt_inc_hp_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "% increase in all monster's hitpoints.", "lbl_inc_hp", 406.0, 20.0, NUI_HALIGN_LEFT); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "***** WARNING! The options below may break the module! *****", "lbl_warning", 450.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can wander upto ", "chbx_wander", 220.0, 20.0, "chbx_warning_tooltip"); + jGroupRow = CreateTextEditBox(jGroupRow, "sPlaceHolder", "txt_wander_distance", 2, FALSE, 35.0f, 20.0f, "chbx_warning_tooltip"); + jGroupRow = CreateLabel(jGroupRow, "meters and ", "lbl_wander_distance", 80.0f, 20.0f, NUI_HALIGN_LEFT, NUI_VALIGN_MIDDLE, 0.0, "chbx_warning_tooltip"); + jGroupRow = CreateCheckBox(jGroupRow, "open doors.", "chbx_open_doors", 100.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Monsters can summon companions.", "chbx_companions", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Summoned associates to remain after masters death.", "chbx_perm_assoc", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateCheckBox(JsonArray(), " Make enemy corpses remain.", "chbx_corpses_stay", 450.0, 20.0, "chbx_warning_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_perc_dist", 450.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "lbl_perc_dist_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight += 364.0; + } + jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + string sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + jLocations = JsonObjectGet(jLocations, "dm" + AI_MAIN_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, "dm" + AI_MAIN_NUI, sName + " PEPS Main Menu", + fX, fY, 534.0f, fHeight, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui_dm"); + // Save the associate to the nui for use in 0e_nui + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oPC))); + NuiSetUserData(oPC, nToken, jData); + object oModule = GetModule(); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 - Version label. + // Row 2 + int nUsing; + // Check the monster AI. + string sLocation = ResManGetAliasFor("ai_default", RESTYPE_NCS); + if(sLocation != "") + { + nUsing = TRUE; + string sLocation = ResManGetAliasFor("nw_c2_default1", RESTYPE_NCS); + if(sLocation != "OVERRIDE:" && sLocation != "PATCH:peps" && sLocation != "DEVELOPMENT:") nUsing = FALSE; + if(nUsing) sText = "Monster AI working"; + else sText = "Monster AI not working"; + } + else sText = "Monster AI not loaded"; + // Check the associate AI. + sLocation = ResManGetAliasFor("ai_a_default", RESTYPE_NCS); + if(sLocation != "") + { + nUsing = TRUE; + string sLocation = ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS); + if(sLocation != "OVERRIDE:" && sLocation != "PATCH:peps" && sLocation != "DEVELOPMENT:") nUsing = FALSE; + if(nUsing) sText += ", Associate AI working"; + else sText += ", Associate AI not working"; + } + else sText += ", Associate AI not loaded"; + // Check for PRC. + sLocation = ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS); + if(sLocation != "") sText += ", PRC loaded."; + else + { + // Check the player AI. + sLocation = ResManGetAliasFor("xx_pc_1_hb", RESTYPE_NCS); + if(sLocation != "") sText += ", Player AI loaded."; + else sText += ", Player AI not loaded."; + } + NuiSetBind(oPC, nToken, "lbl_ai_info_label", JsonString(sText)); + // Row 3 + NuiSetBind(oPC, nToken, "btn_plugin_manager_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_plugin_manager_tooltip", JsonString(" Manages external executable scripts.")); + NuiSetBind(oPC, nToken, "btn_widget_manager_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_manager_tooltip", JsonString(" Manages widgets the players have access to.")); + // Row 3 Label for AI RULES + // Row 4 + NuiSetBind(oPC, nToken, "txt_max_henchman_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_max_henchman", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_MAX_HENCHMAN)))); + NuiSetBindWatch (oPC, nToken, "txt_max_henchman", TRUE); + NuiSetBind(oPC, nToken, "txt_max_henchman_tooltip", JsonString(" Set max number of henchman allowed (1-12).")); + NuiSetBind(oPC, nToken, "txt_xp_scale_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_xp_scale", JsonString(IntToString(GetModuleXPScale()))); + NuiSetBindWatch (oPC, nToken, "txt_xp_scale", TRUE); + NuiSetBind(oPC, nToken, "txt_xp_scale_tooltip", JsonString(" Set the modules XP scale (0 - 200) Normal D&D is 10.")); + NuiSetBind(oPC, nToken, "chbx_party_scale_check", JsonBool(GetLocalInt(oModule, AI_RULE_PARTY_SCALE))); + NuiSetBindWatch(oPC, nToken, "chbx_party_scale_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_party_scale_event", JsonBool(TRUE)); + sText = IntToString(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP)); + NuiSetBind(oPC, nToken, "chbx_party_scale_tooltip", JsonString(" PEPS adjusts your XP based on party size from (" + sText + ").")); + NuiSetBind(oPC, nToken, "btn_default_xp_event", JsonBool(TRUE)); + sText = IntToString(GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE)); + NuiSetBind(oPC, nToken, "btn_default_xp_tooltip", JsonString(" Reset the Modules XP to (" + sText + ").")); + if(nMonsterAI) + { + NuiSetBind(oPC, nToken, "txt_ai_difficulty_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_ai_difficulty", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_AI_DIFFICULTY)))); + NuiSetBindWatch(oPC, nToken, "txt_ai_difficulty", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_monsters_check", JsonBool(GetLocalInt(oModule, AI_RULE_BUFF_MONSTERS))); + NuiSetBindWatch(oPC, nToken, "chbx_buff_monsters_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_monsters_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_buff_summons_check", JsonBool(GetLocalInt(oModule, AI_RULE_PRESUMMON))); + NuiSetBindWatch(oPC, nToken, "chbx_buff_summons_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_summons_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_ambush_monsters_check", JsonBool(GetLocalInt(oModule, AI_RULE_AMBUSH))); + NuiSetBindWatch(oPC, nToken, "chbx_ambush_monsters_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ambush_monsters_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_companions_check", JsonBool(GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS))); + NuiSetBindWatch(oPC, nToken, "chbx_companions_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_companions_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_companions_tooltip", JsonString(" ** This will break some modules! ** See Readme for issues!")); + NuiSetBind(oPC, nToken, "chbx_perm_assoc_check", JsonBool(GetLocalInt(oModule, AI_RULE_PERM_ASSOC))); + NuiSetBindWatch(oPC, nToken, "chbx_perm_assoc_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_perm_assoc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_corpses_stay_check", JsonBool(GetLocalInt(oModule, AI_RULE_CORPSES_STAY))); + NuiSetBindWatch(oPC, nToken, "chbx_corpses_stay_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_corpses_stay_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_corpses_stay_tooltip", JsonString(" ** This will break some modules! ** See Readme for issues!")); + NuiSetBind(oPC, nToken, "txt_perception_distance_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_perception_distance", JsonString(FloatToString(GetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE), 0, 0))); + NuiSetBindWatch(oPC, nToken, "txt_perception_distance", TRUE); + NuiSetBind(oPC, nToken, "txt_perception_distance_tooltip", JsonString(" Range [10 to 60 meters] from the player.")); + NuiSetBindWatch(oPC, nToken, "lbl_perc_dist", TRUE); + int nPercDist = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE); + if(nPercDist < 8 || nPercDist > 11) + { + nPercDist = 11; + SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, 11); + } + if(nPercDist == 8) sText = " Monster perception: Short [10 Sight / 10 Listen]"; + else if(nPercDist == 9) sText = " Monster perception: Medium [20 Sight / 20 Listen]"; + else if(nPercDist == 10) sText = " Monster perception: Long [35 Sight / 20 Listen]"; + else sText = " Monster perception: Default [Monster's default values]"; + NuiSetBind(oPC, nToken, "lbl_perc_dist_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "lbl_perc_dist_tooltip", JsonString(" Use the mouse wheel to change values.")); + int bWander = GetLocalInt(oModule, AI_RULE_WANDER); + NuiSetBind(oPC, nToken, "chbx_wander_check", JsonBool(bWander)); + NuiSetBindWatch(oPC, nToken, "chbx_wander_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_wander_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_wander_distance_event", JsonBool(bWander)); + NuiSetBind(oPC, nToken, "txt_wander_distance", JsonString(FloatToString(GetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE), 0, 0))); + NuiSetBindWatch(oPC, nToken, "txt_wander_distance", TRUE); + NuiSetBind(oPC, nToken, "chbx_wander_tooltip", JsonString(" ** This will break some modules! ** See Readme for issues!")); + NuiSetBind(oPC, nToken, "chbx_open_doors_check", JsonBool(GetLocalInt(oModule, AI_RULE_OPEN_DOORS))); + NuiSetBindWatch(oPC, nToken, "chbx_open_doors_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_open_doors_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_open_doors_tooltip", JsonString(" This allows monsters to open doors to hunt you down!")); + NuiSetBind(oPC, nToken, "txt_inc_enc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_inc_enc_tooltip", JsonString(" Spawns one extra monster per counter above 1. Adds value to counter per encounter monster spawned.")); + NuiSetBind(oPC, nToken, "txt_inc_enc", JsonString(FloatToString(GetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS), 0, 2))); + NuiSetBindWatch(oPC, nToken, "txt_inc_enc", TRUE); + NuiSetBind(oPC, nToken, "txt_inc_hp_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_inc_hp", JsonString(IntToString(GetLocalInt(oModule, AI_INCREASE_MONSTERS_HP)))); + NuiSetBindWatch(oPC, nToken, "txt_inc_hp", TRUE); + } + if(nMonsterAI || nAssociateAI) + { + NuiSetBind(oPC, nToken, "chbx_moral_check", JsonBool(GetLocalInt(oModule, AI_RULE_MORAL_CHECKS))); + NuiSetBindWatch (oPC, nToken, "chbx_moral_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_moral_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_advanced_movement_check", JsonBool(GetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT))); + NuiSetBindWatch (oPC, nToken, "chbx_advanced_movement_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_advanced_movement_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_ilr_check", JsonBool(GetLocalInt(oModule, AI_RULE_ILR))); + NuiSetBindWatch (oPC, nToken, "chbx_ilr_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ilr_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_umd_check", JsonBool(GetLocalInt(oModule, AI_RULE_ALLOW_UMD))); + NuiSetBindWatch (oPC, nToken, "chbx_umd_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_umd_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_use_healingkits_check", JsonBool(GetLocalInt(oModule, AI_RULE_HEALERSKITS))); + NuiSetBindWatch (oPC, nToken, "chbx_use_healingkits_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_use_healingkits_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_darkness_check", JsonBool(ai_SpellRestricted(SPELL_DARKNESS))); + NuiSetBindWatch (oPC, nToken, "chbx_darkness_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_darkness_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_darkness_tooltip", JsonString(" AI will not use the Darkness spell in combat.")); + NuiSetBind(oPC, nToken, "chbx_dispels_check", JsonBool(ai_SpellRestricted(SPELL_DISPEL_MAGIC))); + NuiSetBindWatch (oPC, nToken, "chbx_dispels_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_dispels_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_dispels_tooltip", JsonString(" AI will not use any of the Dispel spells in combat.")); + NuiSetBind(oPC, nToken, "chbx_timestop_check", JsonBool(ai_SpellRestricted(SPELL_TIME_STOP))); + NuiSetBindWatch (oPC, nToken, "chbx_timestop_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_timestop_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_timestop_tooltip", JsonString(" AI will not use the Time Stop spell in combat.")); + } +} +void ai_CreateDMCommandNUI(object oPC) +{ + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 73 + json jRow = CreateButtonSelect(JsonArray(), "Lock Widget", "btn_widget_lock", 200.0, 20.0, "btn_widget_lock_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_1", 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Main Menu", "btn_main_menu", 200.0, 20.0, -1.0, "btn_main_menu_tooltip"); + jRow = CreateLabel(jRow, "", "blank_label_2", 25.0, 20.0); + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 101 + jRow = CreateButton(JsonArray(), "", "btn_cmd_group1", 200.0, 20.0, -1.0, "btn_cmd_group1_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group1", 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "", "btn_cmd_group2", 200.0, 20.0, -1.0, "btn_cmd_group2_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group2", 25.0, 20.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 500 / 129 + jRow = CreateButton(JsonArray(), "", "btn_cmd_group3", 200.0, 20.0, -1.0, "btn_cmd_group3_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group3", 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "", "btn_cmd_group4", 200.0, 20.0, -1.0, "btn_cmd_group4_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group4", 25.0, 20.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 500 / 157 + jRow = CreateButton(JsonArray(), "", "btn_cmd_group5", 200.0, 20.0, -1.0, "btn_cmd_group5_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group5", 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "", "btn_cmd_group6", 200.0, 20.0, -1.0, "btn_cmd_group6_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_group6", 25.0, 20.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 157.0; + // Row 5 ******************************************************************* 500 / --- + jRow = CreateButton(JsonArray(), "Toggle Camera Focus", "btn_camera", 200.0, 20.0, -1.0, "btn_camera_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_camera", 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Open/Close Inventory", "btn_inventory", 200.0, 20.0, -1.0, "btn_inventory_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_inventory", 25.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + // Row 6+ ****************************************************************** 500 / --- + json jDMPlugins = ai_UpdatePluginsForDM(oPC); + // Set the plugins the dm can use. + int nIndex; + string sButton, sName; + json jPlugin = JsonArrayGet(jDMPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(JsonArray(), sName, "btn_plugin_" + sButton, 200.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0, "chbx_plugin_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jPlugin = JsonArrayGet(jDMPlugins, ++nIndex); + if(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(jRow, sName, "btn_plugin_" + sButton, 200.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0, "chbx_plugin_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + else + { + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + break; + } + jPlugin = JsonArrayGet(jDMPlugins, ++nIndex); + } + // Row 7 ****************************************************************** 500 / --- + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "", "lbl_info_1", 475.0, 20.0, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight = fHeight + 28.0; + // Get the window location to restore it from the database. + sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + jLocations = JsonObjectGet(jLocations, "dm" + AI_COMMAND_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sDMName = GetName(oPC); + if(GetStringRight(sDMName, 1) == "s") sDMName = sDMName + "'"; + else sDMName = sDMName + "'s"; + int nToken = SetWindow(oPC, jLayout, "dm" + AI_COMMAND_NUI, sDMName + " Command Menu", + fX, fY, 500.0, fHeight + 12.0, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui_dm"); + // Get which buttons are activated. + int bAIWidgetLock = ai_GetDMWidgetButton(oPC, BTN_DM_WIDGET_LOCK); + int bCmdGroup1 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP1); + int bCmdGroup2 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP2); + int bCmdGroup3 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP3); + int bCmdGroup4 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP4); + int bCmdGroup5 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP5); + int bCmdGroup6 = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_GROUP6); + int bCmdCamera = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_CAMERA); + int bCmdInventory = ai_GetDMWidgetButton(oPC, BTN_DM_CMD_INVENTORY); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set all binds, events, and watches. + // Row 1 + NuiSetBind(oPC, nToken, "btn_widget_lock_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_widget_lock", JsonBool(bAIWidgetLock)); + NuiSetBind(oPC, nToken, "btn_widget_lock_tooltip", JsonString( + " Locks widget to the current location.")); + NuiSetBind(oPC, nToken, "btn_main_menu_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_main_menu", JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_main_menu_tooltip", JsonString(" Server menu options")); + NuiSetBind(oPC, nToken, "btn_group_options_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_group_options", JsonInt(TRUE)); + //NuiSetBind(oPC, nToken, "btn_empty_button_event", JsonBool (TRUE)); + //NuiSetBind(oPC, nToken, "btn_empty_button", JsonInt(TRUE)); + //sText = " Copy AI and command settings for one creature to others."; + //NuiSetBind(oPC, nToken, "btn_empty_button_tooltip", JsonString(sText)); + // Row 2 + NuiSetBind(oPC, nToken, "chbx_cmd_group1_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group1_check", JsonBool (bCmdGroup1)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group1_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group1_event", JsonBool (TRUE)); + string sText, sText2, sSpeed; + string sAction = " (Left Action/Right Add)"; + json jGroup = GetLocalJson(oPC, "DM_GROUP1"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + string sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 1"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group1_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group1_tooltip", JsonString(" " + sText2)); + NuiSetBind(oPC, nToken, "chbx_cmd_group2_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group2_check", JsonBool (bCmdGroup2)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group2_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group2_event", JsonBool (TRUE)); + jGroup = GetLocalJson(oPC, "DM_GROUP2"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 2"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group2_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group2_tooltip", JsonString(" " + sText2)); + // Row 3 + NuiSetBind(oPC, nToken, "chbx_cmd_group3_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group3_check", JsonBool (bCmdGroup3)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group3_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group3_event", JsonBool (TRUE)); + jGroup = GetLocalJson(oPC, "DM_GROUP3"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 3"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group3_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group3_tooltip", JsonString(" " + sText2)); + NuiSetBind(oPC, nToken, "chbx_cmd_group4_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group4_check", JsonBool (bCmdGroup4)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group4_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group4_event", JsonBool (TRUE)); + jGroup = GetLocalJson(oPC, "DM_GROUP4"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 4"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group4_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group4_tooltip", JsonString(" " + sText2)); + // Row 4 + NuiSetBind(oPC, nToken, "chbx_cmd_group5_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group5_check", JsonBool (bCmdGroup5)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group5_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group5_event", JsonBool (TRUE)); + jGroup = GetLocalJson(oPC, "DM_GROUP5"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 5"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group5_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group5_tooltip", JsonString(" " + sText2)); + NuiSetBind(oPC, nToken, "chbx_cmd_group6_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_cmd_group6_check", JsonBool (bCmdGroup6)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_group6_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cmd_group6_event", JsonBool (TRUE)); + jGroup = GetLocalJson(oPC, "DM_GROUP6"); + if(JsonGetInt(JsonArrayGet(jGroup, 0)) == 0) sSpeed = " [Walk]"; + else sSpeed = " [Run]"; + sUUID = JsonGetString(JsonArrayGet(jGroup, 1)); + if(sUUID == "") { sText = "Group 6"; sText2 = sText + sAction; } + else { sText = GetName(GetObjectByUUID(sUUID)) + "'s group"; sText2 = sText + sSpeed; } + NuiSetBind(oPC, nToken, "btn_cmd_group6_label", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_cmd_group6_tooltip", JsonString(" " + sText2)); + // Row 5 + NuiSetBind(oPC, nToken, "chbx_camera_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_camera_check", JsonBool (bCmdCamera)); + NuiSetBindWatch (oPC, nToken, "chbx_camera_check", TRUE); + NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString ( + " Toggle camera view for " + sDMName)); + NuiSetBind(oPC, nToken, "chbx_inventory_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "chbx_inventory_check", JsonBool (bCmdInventory)); + NuiSetBindWatch (oPC, nToken, "chbx_inventory_check", TRUE); + NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString ( + " Open " + sDMName + " inventory")); + // Row 6+ + nIndex = 0; + int bWidget; + jPlugin = JsonArrayGet(jDMPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_event", JsonBool(TRUE)); + bWidget = JsonGetInt(JsonArrayGet(jPlugin, 1)); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_check", JsonBool(bWidget)); + NuiSetBindWatch (oPC, nToken, "chbx_plugin_" + sButton + "_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_event", JsonBool(TRUE)); + sText = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_tooltip", JsonString(sText)); + jPlugin = JsonArrayGet(jDMPlugins, ++nIndex); + } + NuiSetBind(oPC, nToken, "chbx_plugin_tooltip", JsonString(" Adds the plugin to your widget.")); + // Row 7 + sText = ai_GetRandomDMTip(); + NuiSetBind(oPC, nToken, "lbl_info_1_label", JsonString(sText)); +} +void ai_CreateDMPluginManagerNUI(object oPC) +{ + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // Row 1 ******************************************************************* 500 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Load All Plugins", "btn_load_plugins", 150.0f, 20.0f, -1.0, "btn_load_plugins_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Check All", "btn_check_plugins", 150.0f, 20.0f, -1.0, "btn_check_plugins_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear All", "btn_clear_plugins", 150.0f, 20.0f, -1.0, "btn_clear_plugins_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 101 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Add Plugin", "btn_add_plugin", 150.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateTextEditBox(jRow, "sPlaceHolder", "txt_plugin", 16, FALSE, 310.0f, 20.0f, "txt_plugin_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 101.0; + // Row 3+ ****************************************************************** 500 / --- + json jPlugins = ai_GetCampaignDbJson("plugins"); + int nIndex = 0; + json jPlugin = JsonArrayGet(jPlugins, nIndex); + string sName, sButton; + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Remove Plugin", "btn_remove_plugin_" + sButton, 150.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + sName = JsonGetString(JsonArrayGet(jPlugin, 2)); + jRow = CreateButton(jRow, sName, "btn_plugin_" + sButton, 290.0f, 20.0f, -1.0, "btn_plugin_" + sButton + "_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_plugin_" + sButton, 25.0, 20.0); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + // Get the window location to restore it from the database. + sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + jLocations = JsonObjectGet(jLocations, "dm" + AI_PLUGIN_NUI); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, "dm" + AI_PLUGIN_NUI, sName + " PEPS Plugin Manager", + fX, fY, 500.0f, fHeight + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui_dm"); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Row 1 + NuiSetBind(oPC, nToken, "btn_load_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_load_plugins_tooltip", JsonString(" Load all known PEPS plugins that are in the game files.")); + NuiSetBind(oPC, nToken, "btn_check_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_check_plugins_tooltip", JsonString(" Add all plugins to the players widget.")); + NuiSetBind(oPC, nToken, "btn_clear_plugins_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_plugins_tooltip", JsonString(" Remove all plugins from the players widget.")); + // Row 2 + NuiSetBind(oPC, nToken, "btn_add_plugin_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_plugin_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_plugin_tooltip", JsonString(" Enter an executable script name.")); + // Row 3+ + nIndex = 0; + int bCheck; + string sText; + jPlugin = JsonArrayGet(jPlugins, nIndex); + while(JsonGetType(jPlugin) != JSON_TYPE_NULL) + { + sButton = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_remove_plugin_" + sButton + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_event", JsonBool(TRUE)); + bCheck = JsonGetInt(JsonArrayGet(jPlugin, 1)); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_check", JsonBool(bCheck)); + NuiSetBind(oPC, nToken, "chbx_plugin_" + sButton + "_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_plugin_" + sButton + "_check", TRUE); + sText = " " + JsonGetString(JsonArrayGet(jPlugin, 2)); + NuiSetBind(oPC, nToken, "btn_plugin_" + sButton + "_tooltip", JsonString(sText)); + jPlugin = JsonArrayGet(jPlugins, ++nIndex); + } + NuiSetBind(oPC, nToken, "chbx_plugin_tooltip", JsonString(" Allows players to use this plugin.")); +} +void ai_CreateDMWidgetManagerNUI(object oPC) +{ + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // Row 1 ******************************************************************* 575 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Check All", "btn_check_buttons", 150.0f, 20.0f, -1.0, "btn_check_buttons_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear All", "btn_clear_buttons", 150.0f, 20.0f, -1.0, "btn_clear_buttons_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 575 / 96 + jRow = CreateLabel(JsonArray(), "This menu manages the PEPS buttons a player may have access to.", "lbl_info1", 636.0, 15.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 575 / 119 + jRow = CreateLabel(JsonArray(), "Having a check next to a button will remove that button from the players menus.", "lbl_info2", 636.0, 15.0); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 575 / 162 + jRow = CreateButtonImage(JsonArray(), "ir_action", "btn_cmd_action", 35.0f, 35.0f, 0.0, "btn_cmd_action_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_action", 25.0, 20.0, "btn_cmd_action_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_guard", "btn_cmd_guard", 35.0f, 35.0f, 0.0, "btn_cmd_guard_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_guard", 25.0, 20.0, "btn_cmd_guard_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_standground", "btn_cmd_hold", 35.0f, 35.0f, 0.0, "btn_cmd_hold_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_hold", 25.0, 20.0, "btn_cmd_hold_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_attacknearest", "btn_cmd_attack", 35.0f, 35.0f, 0.0, "btn_cmd_attack_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_attack", 25.0, 20.0, "btn_cmd_attack_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_follow", "btn_cmd_follow", 35.0f, 35.0f, 0.0, "btn_cmd_follow_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_follow", 25.0, 20.0, "btn_cmd_follow_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_dmchat", "btn_follow_target", 35.0f, 35.0f, 0.0, "btn_follow_target_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_follow_target", 25.0, 20.0, "btn_follow_target_tooltip"); + + jRow = CreateButtonImage(jRow, "ife_foc_search", "btn_cmd_search", 35.0f, 35.0f, 0.0, "btn_cmd_search_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_search", 25.0, 20.0, "btn_cmd_search_tooltip"); + + jRow = CreateButtonImage(jRow, "ife_foc_hide", "btn_cmd_stealth", 35.0f, 35.0f, 0.0, "btn_cmd_stealth_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_stealth", 25.0, 20.0, "btn_cmd_stealth_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_scommand", "btn_cmd_ai_script", 35.0f, 35.0f, 0.0, "btn_cmd_ai_script_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_ai_script", 25.0, 20.0, "btn_cmd_ai_script_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_settrap", "btn_cmd_place_trap", 35.0f, 35.0f, 0.0, "btn_cmd_place_trap_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cmd_place_trap", 25.0, 20.0, "btn_cmd_place_trap_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 ******************************************************************* 575 / 205 + jRow = CreateButtonImage(JsonArray(), "isk_spellcraft", "btn_quick_widget", 35.0f, 35.0f, 0.0, "btn_quick_widget_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_quick_widget", 25.0, 20.0, "btn_quick_widget_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_lore", "btn_spell_memorize", 35.0f, 35.0f, 0.0, "btn_spell_memorize_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_spell_memorize", 25.0, 20.0, "btn_spell_memorize_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_cantrips", "btn_buff_short", 35.0f, 35.0f, 0.0, "btn_buff_short_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_short", 25.0, 20.0, "btn_buff_short_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_cast", "btn_buff_long", 35.0f, 35.0f, 0.0, "btn_buff_long_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_long", 25.0, 20.0, "btn_buff_long_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_level789", "btn_buff_all", 35.0f, 35.0f, 0.0, "btn_buff_all_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_all", 25.0, 20.0, "btn_buff_all_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_rest", "btn_buff_rest", 35.0f, 35.0f, 0.0, "btn_buff_rest_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_buff_rest", 25.0, 20.0, "btn_buff_rest_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_jump", "btn_jump_to", 35.0f, 35.0f, 0.0, "btn_jump_to_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_jump_to", 25.0, 20.0, "btn_jump_to_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_limbo", "btn_ghost_mode", 35.0f, 35.0f, 0.0, "btn_ghost_mode_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ghost_mode", 25.0, 20.0, "btn_ghost_mode_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_examine", "btn_camera", 35.0f, 35.0f, 0.0, "btn_camera_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_camera", 25.0, 20.0, "btn_camera_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_pickup", "btn_inventory", 35.0f, 35.0f, 0.0, "btn_inventory_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_inventory", 25.0, 20.0, "btn_inventory_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 6 ******************************************************************* 575 / 248 + + jRow = CreateButtonImage(JsonArray(), "ife_familiar", "btn_familiar", 35.0f, 35.0f, 0.0, "btn_familiar_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_familiar", 25.0, 20.0, "btn_familiar_tooltip"); + + jRow = CreateButtonImage(jRow, "ife_animal", "btn_companion", 35.0f, 35.0f, 0.0, "btn_companion_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_companion", 25.0, 20.0, "btn_companion_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_ai", "btn_ai", 35.0f, 35.0f, 0.0, "btn_ai_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ai", 25.0, 20.0, "btn_companion_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_movsilent", "btn_quiet", 35.0f, 35.0f, 0.0, "btn_quiet_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_quiet", 25.0, 20.0, "btn_quiet_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_archer", "btn_ranged", 35.0f, 35.0f, 0.0, "btn_ranged_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ranged", 25.0, 20.0, "btn_ranged_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_takeitem", "btn_equip_weapon", 35.0f, 35.0f, 0.0, "btn_equip_weapon_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_equip_weapon", 25.0, 20.0, "btn_equip_weapon_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_search", "btn_search", 35.0f, 35.0f, 0.0, "btn_search_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_search", 25.0, 20.0, "btn_search_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_hide", "btn_stealth", 35.0f, 35.0f, 0.0, "btn_stealth_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_stealth", 25.0, 20.0, "btn_stealth_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_open", "btn_open_door", 35.0f, 35.0f, 0.0, "btn_open_door_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_open_door", 25.0, 20.0, "btn_open_door_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_distrap", "btn_traps", 35.0f, 35.0f, 0.0, "btn_traps_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_traps", 25.0, 20.0, "btn_traps_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 7 ******************************************************************* 575 / 291 + + jRow = CreateButtonImage(JsonArray(), "isk_olock", "btn_pick_locks", 35.0f, 35.0f, 0.0, "btn_pick_locks_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_pick_locks", 25.0, 20.0, "btn_pick_locks_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_bash", "btn_bash_locks", 35.0f, 35.0f, 0.0, "btn_bash_locks_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_bash_locks", 25.0, 20.0, "btn_bash_locks_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_control", "btn_magic_level", 35.0f, 35.0f, 0.0, "btn_magic_level_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic_level", 25.0, 20.0, "btn_magic_level_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_xability", "btn_spontaneous", 35.0f, 35.0f, 0.0, "btn_spontaneous_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_spontaneous", 25.0, 20.0, "btn_spontaneous_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_cntrspell", "btn_magic", 35.0f, 35.0f, 0.0, "btn_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic", 25.0, 20.0, "btn_magic_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_moreattacks", "btn_magic_items", 35.0f, 35.0f, 0.0, "btn_magic_items_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_magic_items", 25.0, 20.0, "btn_magic_items_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_orisons", "btn_def_magic", 35.0f, 35.0f, 0.0, "btn_def_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_def_magic", 25.0, 20.0, "btn_def_magic_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_metamagic", "btn_off_magic", 35.0f, 35.0f, 0.0, "btn_off_magic_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_off_magic", 25.0, 20.0, "btn_off_magic_tooltip"); + + jRow = CreateButtonImage(jRow, "isk_heal", "btn_heal_out", 35.0f, 35.0f, 0.0, "btn_heal_out_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heal_out", 25.0, 20.0, "btn_heal_out_tooltip"); + + jRow = CreateButtonImage(jRow, "dm_heal", "btn_heal_in", 35.0f, 35.0f, 0.0, "btn_heal_in_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heal_in", 25.0, 20.0, "btn_heal_in_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 8 ******************************************************************* 575 / 334 + jRow = CreateButtonImage(JsonArray(), "ir_heal", "btn_heals_onoff", 35.0f, 35.0f, 0.0, "btn_heals_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_heals_onoff", 25.0, 20.0, "btn_heals_onoff_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_party", "btn_healp_onoff", 35.0f, 35.0f, 0.0, "btn_healp_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_healp_onoff", 25.0, 20.0, "btn_healp_onoff_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_accept", "btn_cure_onoff", 35.0f, 35.0f, 0.0, "btn_cure_onoff_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_cure_onoff", 25.0, 20.0, "btn_cure_onoff_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_barter", "btn_loot", 35.0f, 35.0f, 0.0, "btn_loot_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_loot", 25.0, 20.0, "btn_loot_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_ignore", "btn_ignore_assoc", 35.0f, 35.0f, 0.0, "btn_ignore_assoc_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ignore_assoc", 25.0, 20.0, "btn_ignore_assoc_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_abort", "btn_ignore_traps", 35.0f, 35.0f, 0.0, "btn_ignore_traps_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_ignore_traps", 25.0, 20.0, "btn_ignore_traps_tooltip"); + + jRow = CreateButtonImage(jRow, "ir_dmchat", "btn_perc_range", 35.0f, 35.0f, 0.0, "btn_perc_range_tooltip"); + jRow = CreateCheckBox(jRow, "", "chbx_perc_range", 25.0, 20.0, "btn_perc_range_tooltip"); + + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 334.0; + // Get the window location to restore it from the database. + string sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + jLocations = JsonObjectGet(jLocations, "dm_widget_manager_nui"); + float fX = JsonGetFloat(JsonObjectGet(jLocations, "x")); + float fY = JsonGetFloat(JsonObjectGet(jLocations, "y")); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, "dm_widget_manager_nui", sName + " PEPS DM Widget Manager", + fX, fY, 660.0f, fHeight + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui_dm"); + // Set event watches for save window location. + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Row 1 + NuiSetBind(oPC, nToken, "btn_check_buttons_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_check_buttons_tooltip", JsonString(" Check all buttons, removing them for all players.")); + NuiSetBind(oPC, nToken, "btn_clear_buttons_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_buttons_tooltip", JsonString(" Clear all buttons, allowing use for all players.")); + // Row 2 & 3 Labels. + // Load all the buttons states. + //int bAIWidgetLock = ai_GetDMWAccessButton(BTN_WIDGET_LOCK); + int bCmdAction = ai_GetDMWAccessButton(BTN_CMD_ACTION); + int bCmdGuard = ai_GetDMWAccessButton(BTN_CMD_GUARD); + int bCmdHold = ai_GetDMWAccessButton(BTN_CMD_HOLD); + int bCmdSearch = ai_GetDMWAccessButton(BTN_CMD_SEARCH); + int bCmdStealth = ai_GetDMWAccessButton(BTN_CMD_STEALTH); + int bCmdAttack = ai_GetDMWAccessButton(BTN_CMD_ATTACK); + int bCmdFollow = ai_GetDMWAccessButton(BTN_CMD_FOLLOW); + int bCmdAIScript = ai_GetDMWAccessButton(BTN_CMD_AI_SCRIPT); + int bCmdPlacetrap = ai_GetDMWAccessButton(BTN_CMD_PLACE_TRAP); + int bSpellWidget = ai_GetDMWAccessButton(BTN_CMD_SPELL_WIDGET); + int bMemorizeSpells = ai_GetDMWAccessButton(BTN_DM_CMD_MEMORIZE); + int bBuffShort = ai_GetDMWAccessButton(BTN_BUFF_SHORT); + int bBuffLong = ai_GetDMWAccessButton(BTN_BUFF_LONG); + int bBuffAll = ai_GetDMWAccessButton(BTN_BUFF_ALL); + int bBuffRest = ai_GetDMWAccessButton(BTN_BUFF_REST); + int bJumpTo = ai_GetDMWAccessButton(BTN_CMD_JUMP_TO); + int bGhostMode = ai_GetDMWAccessButton(BTN_CMD_GHOST_MODE); + int bCamera = ai_GetDMWAccessButton(BTN_CMD_CAMERA); + int bInventory = ai_GetDMWAccessButton(BTN_CMD_INVENTORY); + int bFamiliar = ai_GetDMWAccessButton(BTN_CMD_FAMILIAR); + int bCompanion = ai_GetDMWAccessButton(BTN_CMD_COMPANION); + int bFollowTarget = ai_GetDMAIAccessButton(BTN_AI_FOLLOW_TARGET); + int bAI = ai_GetDMAIAccessButton(BTN_AI_FOR_PC); + int bReduceSpeech = ai_GetDMAIAccessButton(BTN_AI_REDUCE_SPEECH); + int bRanged = ai_GetDMAIAccessButton(BTN_AI_USE_RANGED); + int bEquipWeapons = ai_GetDMAIAccessButton(BTN_AI_STOP_WEAPON_EQUIP); + int bSearch = ai_GetDMAIAccessButton(BTN_AI_USE_SEARCH); + int bStealth = ai_GetDMAIAccessButton(BTN_AI_USE_STEALTH); + int bOpenDoors = ai_GetDMAIAccessButton(BTN_AI_OPEN_DOORS); + int bTraps = ai_GetDMAIAccessButton(BTN_AI_REMOVE_TRAPS); + int bPickLocks = ai_GetDMAIAccessButton(BTN_AI_PICK_LOCKS); + int bBashLocks = ai_GetDMAIAccessButton(BTN_AI_BASH_LOCKS); + int bMagicLevel = ai_GetDMAIAccessButton(BTN_AI_MAGIC_LEVEL); + int bSpontaneous = ai_GetDMAIAccessButton(BTN_AI_NO_SPONTANEOUS); + int bNoMagic = ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_USE); + int bNoMagicItems = ai_GetDMAIAccessButton(BTN_AI_NO_MAGIC_ITEM_USE); + int bDefMagic = ai_GetDMAIAccessButton(BTN_AI_DEF_MAGIC_USE); + int bOffMagic = ai_GetDMAIAccessButton(BTN_AI_OFF_MAGIC_USE); + int bHealOut = ai_GetDMAIAccessButton(BTN_AI_HEAL_OUT); + int bHealIn = ai_GetDMAIAccessButton(BTN_AI_HEAL_IN); + int bSelfHealOnOff = ai_GetDMAIAccessButton(BTN_AI_STOP_SELF_HEALING); + int bPartyHealOnOff = ai_GetDMAIAccessButton(BTN_AI_STOP_PARTY_HEALING); + int bCureOnOff = ai_GetDMAIAccessButton(BTN_AI_STOP_CURE_SPELLS); + int bLoot = ai_GetDMAIAccessButton(BTN_AI_LOOT); + int bIgnoreAssociates = ai_GetDMAIAccessButton(BTN_AI_IGNORE_ASSOCIATES); + int bIgnoreTraps = ai_GetDMAIAccessButton(BTN_AI_IGNORE_TRAPS); + int bPercRange = ai_GetDMAIAccessButton(BTN_AI_PERC_RANGE); + int bBtnFamiliar = ai_GetDMWAccessButton(BTN_CMD_FAMILIAR); + int bBtnCompanion = ai_GetDMWAccessButton(BTN_CMD_COMPANION); + SetLocalInt(oPC, "CHBX_SKIP", TRUE); + DelayCommand(2.0, DeleteLocalInt(oPC, "CHBX_SKIP")); + // Row 4 + NuiSetBind(oPC, nToken, "chbx_cmd_action_check", JsonBool (bCmdAction)); + NuiSetBindWatch(oPC, nToken, "chbx_cmd_action_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_action_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_action_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_action_tooltip", JsonString(" Action button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_guard_check", JsonBool (bCmdGuard)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_guard_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_guard_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_guard_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_guard_tooltip", JsonString(" Guard button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_hold_check", JsonBool (bCmdHold)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_hold_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_hold_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_hold_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_hold_tooltip", JsonString(" Hold button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_attack_check", JsonBool (bCmdAttack)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_attack_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_attack_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_attack_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_attack_tooltip", JsonString(" Attack button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_follow_check", JsonBool (bCmdFollow)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_follow_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_follow_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_follow_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_follow_tooltip", JsonString(" Follow button")); + + NuiSetBind(oPC, nToken, "chbx_follow_target_check", JsonBool (bFollowTarget)); + NuiSetBindWatch (oPC, nToken, "chbx_follow_target_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_follow_target_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_follow_target_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_follow_target_tooltip", JsonString(" Follow Target button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_search_check", JsonBool (bCmdSearch)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_search_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_search_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_search_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_search_tooltip", JsonString(" Search All button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_stealth_check", JsonBool (bCmdStealth)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_stealth_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_stealth_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_stealth_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_stealth_tooltip", JsonString(" Stealth All button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_ai_script_check", JsonBool (bCmdAIScript)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_ai_script_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_ai_script_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_ai_script_tooltip", JsonString(" Combat Tactics button")); + + NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_check", JsonBool (bCmdPlacetrap)); + NuiSetBindWatch (oPC, nToken, "chbx_cmd_place_trap_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_cmd_place_trap_tooltip", JsonString (" Place Trap button")); + // Row 5 + NuiSetBind(oPC, nToken, "chbx_quick_widget_check", JsonBool (bSpellWidget)); + NuiSetBindWatch (oPC, nToken, "chbx_quick_widget_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_quick_widget_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_quick_widget_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_quick_widget_tooltip", JsonString(" Quick Use button")); + + NuiSetBind(oPC, nToken, "chbx_spell_memorize_check", JsonBool (bMemorizeSpells)); + NuiSetBindWatch (oPC, nToken, "chbx_spell_memorize_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_spell_memorize_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spell_memorize_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_spell_memorize_tooltip", JsonString(" Memorize Spells button")); + + NuiSetBind(oPC, nToken, "chbx_buff_short_check", JsonBool (bBuffShort)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_short_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_short_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_short_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_buff_short_tooltip", JsonString(" Short Buffing button")); + + NuiSetBind(oPC, nToken, "chbx_buff_long_check", JsonBool (bBuffLong)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_long_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_long_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_long_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_long_tooltip", JsonString(" Long Buffing button")); + + NuiSetBind(oPC, nToken, "chbx_buff_all_check", JsonBool (bBuffAll)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_all_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_all_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_all_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_all_tooltip", JsonString(" All Buffing button")); + + NuiSetBind(oPC, nToken, "chbx_buff_rest_check", JsonBool (bBuffRest)); + NuiSetBindWatch (oPC, nToken, "chbx_buff_rest_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_buff_rest_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_rest_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_buff_rest_tooltip", JsonString(" Rest Buffing button")); + + NuiSetBind(oPC, nToken, "chbx_jump_to_check", JsonBool(bJumpTo)); + NuiSetBindWatch (oPC, nToken, "chbx_jump_to_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_jump_to_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_jump_to_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_jump_to_tooltip", JsonString(" Jump Associates button")); + + NuiSetBind(oPC, nToken, "chbx_ghost_mode_check", JsonBool (bGhostMode)); + NuiSetBindWatch (oPC, nToken, "chbx_ghost_mode_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ghost_mode_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ghost_mode_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_ghost_mode_tooltip", JsonString(" Ghost mode button")); + + NuiSetBind(oPC, nToken, "chbx_camera_check", JsonBool (bCamera)); + NuiSetBindWatch (oPC, nToken, "chbx_camera_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_camera_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString(" Change Camera button")); + + NuiSetBind(oPC, nToken, "chbx_inventory_check", JsonBool (bInventory)); + NuiSetBindWatch (oPC, nToken, "chbx_inventory_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_inventory_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString(" Open Inventory button")); + // Row 6 + NuiSetBind(oPC, nToken, "chbx_familiar_check", JsonBool(bBtnFamiliar)); + NuiSetBindWatch (oPC, nToken, "chbx_familiar_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_familiar_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_familiar_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_familiar_tooltip", JsonString(" Change Familiar buttons")); + + NuiSetBind(oPC, nToken, "chbx_companion_check", JsonBool(bBtnCompanion)); + NuiSetBindWatch (oPC, nToken, "chbx_companion_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_companion_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_companion_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_companion_tooltip", JsonString(" Change Animal Companion buttons")); + + NuiSetBind(oPC, nToken, "chbx_ai_check", JsonBool(bAI)); + NuiSetBindWatch (oPC, nToken, "chbx_ai_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ai_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ai_tooltip", JsonString(" Player AI button")); + + NuiSetBind(oPC, nToken, "chbx_quiet_check", JsonBool(bReduceSpeech)); + NuiSetBindWatch (oPC, nToken, "chbx_quiet_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_quiet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_quiet_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_quiet_tooltip", JsonString(" Reduce Speech button")); + + NuiSetBind(oPC, nToken, "chbx_ranged_check", JsonBool(bRanged)); + NuiSetBindWatch(oPC, nToken, "chbx_ranged_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ranged_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ranged_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_ranged_tooltip", JsonString(" Ranged button")); + + NuiSetBind(oPC, nToken, "chbx_equip_weapon_check", JsonBool(bEquipWeapons)); + NuiSetBindWatch(oPC, nToken, "chbx_equip_weapon_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_equip_weapon_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_equip_weapon_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_equip_weapon_tooltip", JsonString(" Auto Equip Weapons button")); + + NuiSetBind(oPC, nToken, "chbx_search_check", JsonBool(bSearch)); + NuiSetBindWatch (oPC, nToken, "chbx_search_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_search_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_search_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_search_tooltip", JsonString(" Search button")); + + NuiSetBind(oPC, nToken, "chbx_stealth_check", JsonBool(bStealth)); + NuiSetBindWatch(oPC, nToken, "chbx_stealth_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_stealth_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_stealth_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_stealth_tooltip", JsonString(" Stealth button")); + + NuiSetBind(oPC, nToken, "chbx_open_door_check", JsonBool(bOpenDoors)); + NuiSetBindWatch (oPC, nToken, "chbx_open_door_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_open_door_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_open_door_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_open_door_tooltip", JsonString(" Open Door button")); + + NuiSetBind(oPC, nToken, "chbx_traps_check", JsonBool(bTraps)); + NuiSetBindWatch (oPC, nToken, "chbx_traps_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_traps_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_traps_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_traps_tooltip", JsonString(" Disable Traps button")); + // Row 7 + NuiSetBind(oPC, nToken, "chbx_pick_locks_check", JsonBool(bPickLocks)); + NuiSetBindWatch(oPC, nToken, "chbx_pick_locks_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_pick_locks_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_pick_locks_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_pick_locks_tooltip", JsonString(" Pick Locks button")); + + NuiSetBind(oPC, nToken, "chbx_bash_locks_check", JsonBool(bBashLocks)); + NuiSetBindWatch(oPC, nToken, "chbx_bash_locks_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_bash_locks_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_bash_locks_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_bash_locks_tooltip", JsonString(" Bash button")); + + NuiSetBind(oPC, nToken, "chbx_magic_level_check", JsonBool(bMagicLevel)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_level_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_level_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_level_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_magic_level_tooltip", JsonString(" Magic Level button")); + + NuiSetBind(oPC, nToken, "chbx_spontaneous_check", JsonBool(bSpontaneous)); + NuiSetBindWatch (oPC, nToken, "chbx_spontaneous_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_spontaneous_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spontaneous_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spontaneous_tooltip", JsonString(" Spontaneous Spells button")); + + NuiSetBind(oPC, nToken, "chbx_magic_check", JsonBool(bNoMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_tooltip", JsonString(" Use Magic button")); + + NuiSetBind(oPC, nToken, "chbx_magic_items_check", JsonBool(bNoMagicItems)); + NuiSetBindWatch (oPC, nToken, "chbx_magic_items_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_magic_items_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_items_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_magic_items_tooltip", JsonString(" Use Magic Items button")); + + NuiSetBind(oPC, nToken, "chbx_def_magic_check", JsonBool (bDefMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_def_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_def_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_def_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_def_magic_tooltip", JsonString(" Use Defensive Magic button")); + + NuiSetBind(oPC, nToken, "chbx_off_magic_check", JsonBool(bOffMagic)); + NuiSetBindWatch (oPC, nToken, "chbx_off_magic_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_off_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_off_magic_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_off_magic_tooltip", JsonString(" Use Offensive Magic button")); + + NuiSetBind(oPC, nToken, "chbx_heal_out_check", JsonBool(bHealOut)); + NuiSetBindWatch (oPC, nToken, "chbx_heal_out_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heal_out_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_out_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_out_tooltip", JsonString(" Heal Out of Combat button")); + + NuiSetBind(oPC, nToken, "chbx_heal_in_check", JsonBool(bHealIn)); + NuiSetBindWatch (oPC, nToken, "chbx_heal_in_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heal_in_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_in_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_in_tooltip", JsonString(" Heal In Combat button")); + // Row 8 + NuiSetBind(oPC, nToken, "chbx_heals_onoff_check", JsonBool(bSelfHealOnOff)); + NuiSetBindWatch (oPC, nToken, "chbx_heals_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_heals_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heals_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heals_onoff_tooltip", JsonString(" Heal Self On/Off button")); + + NuiSetBind(oPC, nToken, "chbx_healp_onoff_check", JsonBool(bPartyHealOnOff)); + NuiSetBind(oPC, nToken, "chbx_healp_onoff_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_healp_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "btn_healp_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_healp_onoff_tooltip", JsonString(" Heal Party On/Off button")); + + NuiSetBind(oPC, nToken, "chbx_cure_onoff_check", JsonBool(bCureOnOff)); + NuiSetBind(oPC, nToken, "chbx_cure_onoff_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "chbx_cure_onoff_check", TRUE); + NuiSetBind(oPC, nToken, "btn_cure_onoff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cure_onoff_tooltip", JsonString(" Cure Spells On/Off button")); + + NuiSetBind(oPC, nToken, "chbx_loot_check", JsonBool(bLoot)); + NuiSetBindWatch (oPC, nToken, "chbx_loot_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_loot_tooltip", JsonString(" Auto Looting button")); + + NuiSetBind(oPC, nToken, "chbx_ignore_assoc_check", JsonBool(bIgnoreAssociates)); + NuiSetBindWatch(oPC, nToken, "chbx_ignore_assoc_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ignore_assoc_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ignore_assoc_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_ignore_assoc_tooltip", JsonString(" Ignore Associates On/Off button")); + + NuiSetBind(oPC, nToken, "chbx_ignore_traps_check", JsonBool(bIgnoreTraps)); + NuiSetBindWatch(oPC, nToken, "chbx_ignore_traps_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_ignore_traps_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_ignore_traps_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "btn_ignore_traps_tooltip", JsonString(" Ignore Floor Traps On/Off button")); + + NuiSetBind(oPC, nToken, "chbx_perc_range_check", JsonBool(bPercRange)); + NuiSetBindWatch (oPC, nToken, "chbx_perc_range_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_perc_range_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_perc_range_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_perc_range_tooltip", JsonString(" Perception Range button")); +} + diff --git a/src/module/nss/0i_messages.nss b/src/module/nss/0i_messages.nss new file mode 100644 index 0000000..ff01269 --- /dev/null +++ b/src/module/nss/0i_messages.nss @@ -0,0 +1,88 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_messages +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include script for sending messages to files and players on the server. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_constants" +#include "0i_color" +// Sets up a Message on the module to be sent to the log and/or players. +// sTextColor color of text sent to the players and DM's. +// Use AI_COLOR_*. Where * is WHITE, RED, GREEN, BLUE, GRAY, or YELLOW. +// If nLog is TRUE it will send the message to the log file. +// If nToDMs is TRUE it will send the message to all DM's. +// If oPC is set to a player then they will get the message as well. +// Messages delivered by script should be colored as follows. +// _Debug message = COLOR_WHITE +// Generic messages for the player = AI_COLOR_YELLOW +// Negative messages for the player = AI_COLOR_RED +// Positive messages for the player = AI_COLOR_GREEN +// System messages, things that are not part of Dnd = COLOR_GRAY +// Descriptive in game messages = COLOR_BLUE +void ai_SendMessages(string sMessage, string sTextColor = AI_COLOR_YELLOW, object oPC = OBJECT_INVALID, int nToDMs = FALSE, int nLog = FALSE); +// Used for _debugging. Keeps all the information organized. +// Sends info to first pc if true and sends information to log file. +// sScriptName is the name of the script calling this function. +// sLineNumber is the line number of the code calling this function. +// sMessage is the description of the debug being sent. +void ai_Debug(string sScriptName, string sLineNumber, string sMessage); +// A counter to track microseconds in code. Start saves the counter. +void ai_Counter_Start(); +// A counter to track microseconds in code. End displays the time between Start +// and End to the log file. +void ai_Counter_End(string sMessage = ""); + +void ai_SendMessages(string sMessage, string sTextColor = AI_COLOR_YELLOW, object oPC = OBJECT_INVALID, int nToDMs = FALSE, int nLog = FALSE) +{ + // if nLog is TRUE send the message to the log file. + if(nLog) + { + sMessage = ai_StripColorCodes(sMessage); + // Add PC name to log to know who it belongs to. + string sLogPCName; + if(oPC != OBJECT_INVALID) sLogPCName = "(" + GetName(oPC) + ") "; + WriteTimestampedLogEntry("*** MESSAGE: " + sLogPCName + " " + sMessage); + } + sMessage = ai_AddColorToText(sMessage, sTextColor); + if(oPC != OBJECT_INVALID) SendMessageToPC(oPC, sMessage); + // If nToDMs is true send message to the DM's online. + if(nToDMs) SendMessageToAllDMs(sMessage); +} +void ai_Debug(string sScriptName, string sLineNumber, string sMessage) +{ + string sName = GetName(OBJECT_SELF); + if(sName == GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) && + sName != "") + { + sMessage = "(((DEBUG)))[" + sScriptName + " - " + sLineNumber + " ]" + sMessage; + sMessage = ai_StripColorCodes(sMessage); + WriteTimestampedLogEntry(sMessage); + return; + } + //sMessage = "(((DEBUG)))[" + sScriptName + " - " + sLineNumber + " ]" + sMessage; + //sMessage = ai_StripColorCodes(sMessage); + //SendMessageToPC(GetFirstPC(), sMessage); + //WriteTimestampedLogEntry(sMessage); + //if(GetLocalInt(OBJECT_SELF, "AI_DEBUG")) WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Kirrin") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Dorna Trapspringer") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Dire Spider") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Shadow Priest") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Tomi Undergallows") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Thello Colds") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Gert Sigers") WriteTimestampedLogEntry(sMessage); + //if(GetName(OBJECT_SELF) == "Zombie") WriteTimestampedLogEntry(sMessage); +} +void ai_Counter_Start() +{ + SetLocalInt(GetModule(), "0_MSCounter", GetMicrosecondCounter()); +} +void ai_Counter_End(string sMessage = "") +{ + int nTime = GetMicrosecondCounter(); + nTime = nTime - GetLocalInt(GetModule(), "0_MSCounter"); + float fTime = nTime / 1000000.0; + if(AI_DEBUG) ai_Debug("MICROSECOND_COUNTER", "", "Seconds: " + FloatToString(fTime, 0, 10) + + " Microseconds: " + IntToString(nTime) + " " + sMessage); +} diff --git a/src/module/nss/0i_module.nss b/src/module/nss/0i_module.nss new file mode 100644 index 0000000..6d50182 --- /dev/null +++ b/src/module/nss/0i_module.nss @@ -0,0 +1,544 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_module +//////////////////////////////////////////////////////////////////////////////// + Include script for handling event scripts for injecting the systems into a + module for either single player or a server. +*/////////////////////////////////////////////////////////////////////////////// +#include "x2_inc_switches" +#include "0i_associates" +#include "0i_menus" +#include "0i_player_target" +#include "0i_gui_events" +// Add to nw_c2_default9 OnSpawn event script of monsters and +int ai_OnMonsterSpawn(object oCreature); +// Add to nw_ch_ac9 OnSpawn event script of henchman. +void ai_OnAssociateSpawn(object oCreature); +// Run all of the players starting scripts. +// If oPC is passed as Invalid then it will get the firt PC in the game. +void ai_CheckPCStart(object oPC = OBJECT_INVALID); +// Checks to see if we should change the monster via Json. +int ai_ChangeMonster(object oCreature, object oModule); +// Checks to see if we should change the associate via Json. +object ai_ChangeAssociate(object oCreature, object oModule); +// Sets the events for oCreature that is a Monster while playing Infinite Dungeons. +void ai_SetIDMonsterEventScripts(object oCreature); +// Sets the events for oCreature that is a monster in while using the PRC and +// playing Infinite Dungeons. +void ai_SetPRCIDMonsterEventScripts(object oCreature); +// Sets the events for oCreature that is an associate while using the PRC. +void ai_SetPRCAssociateEventScripts(object oCreature); +// Reverts single player monster event scripts back to their default. +void ai_ChangeEventScriptsForMonster(object oCreature); +// Reverts single player associates event scripts back to their default. +void ai_ChangeEventScriptsForAssociate(object oCreature); +// If using PRC this will replace some spells with PRC variants. +json ai_ReplaceSpellsWithPRCVariants(object oCreature, json jCreature); + +//****************************************************************************** +//********************* Creature event scripts ********************************* +//****************************************************************************** +int ai_OnMonsterSpawn(object oCreature) +{ + if(GetLocalInt(oCreature, AI_ONSPAWN_EVENT)) return FALSE; + SetLocalInt(oCreature, AI_ONSPAWN_EVENT, TRUE); + object oModule = GetModule(); + int nInfiniteDungeons; + int nPRC = GetLocalInt(oModule, AI_USING_PRC); + // If you are running a server this will not affect the module. + if(!AI_SERVER) + { + ai_CheckPCStart(); + string sModuleName = GetModuleName(); + if(sModuleName == "Neverwinter Nights - Infinite Dungeons" || + sModuleName == "Infinite Dungeons [PRC8]") + { + nInfiniteDungeons = TRUE; + if(nPRC) ai_SetPRCIDMonsterEventScripts(oCreature); + else ai_SetIDMonsterEventScripts(oCreature); + // Fix to get plot givers, finishers from getting killed a lot. + if(GetLocalString(oCreature, "sConversation") == "id1_plotgiver " || + GetLocalString(oCreature, "sConversation") == "id1_plotdest") + { + ChangeToStandardFaction(oCreature, STANDARD_FACTION_MERCHANT); + SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 50, oCreature); + } + } + } + // PRC and Infinite dungeons has issues with Ondeath script so we just leave it alone. + if(!nPRC && !nInfiniteDungeons) + { + // We change this script so we can setup permanent summons on/off. + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH); + SetLocalString(oCreature, "AI_ON_DEATH", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_c2_7_ondeath"); + } + if(GetCreatureFlag(oCreature, CREATURE_VAR_IS_INCORPOREAL)) + { + string sCombatAI = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + if (sCombatAI == "") SetLocalString(oCreature, AI_DEFAULT_SCRIPT, "ai_incorporeal"); + } + ai_SetListeningPatterns(oCreature); + ai_SetCreatureAIScript(oCreature); + ai_SetNormalAppearance(oCreature); + ai_SetAura(oCreature); + SetLocalInt(oCreature, AI_HEAL_IN_COMBAT_LIMIT, AI_MONSTER_HEAL_IN_COMBAT_CHANCE); + SetLocalInt(oCreature, AI_HEAL_OUT_OF_COMBAT_LIMIT, AI_MONSTER_HEAL_OUT_COMBAT_CHANCE); + int nMonsterHpIncrease = GetLocalInt(oModule, AI_INCREASE_MONSTERS_HP); + if(nMonsterHpIncrease) + { + int nHp = GetMaxHitPoints(oCreature); + nHp = (nHp * nMonsterHpIncrease) / 100; + effect eHp = EffectTemporaryHitpoints(nHp); + eHp = SupernaturalEffect(eHp); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHp, oCreature); + } + // Check if the monster should change how they search for targets. + if(d100() <= GetLocalInt(GetModule(), AI_RULE_AI_DIFFICULTY)) + { + SetLocalInt(oCreature, AI_RULE_AI_DIFFICULTY, TRUE); + } + // Do json changes after we have setup the creature. + if(ai_ChangeMonster(oCreature, oModule)) return TRUE; + return FALSE; +} +void ai_OnAssociateSpawn(object oCreature) +{ + if(GetLocalInt(oCreature, AI_ONSPAWN_EVENT)) return; + SetLocalInt(oCreature, AI_ONSPAWN_EVENT, TRUE); + int bPRC = GetLocalInt(GetModule(), AI_USING_PRC); + // If you are running a server this will not affect the module. + if(!AI_SERVER) + { + if(bPRC) ai_SetPRCAssociateEventScripts(oCreature); + } + // PRC has issues with Ondeath script so we just leave it alone. + if(!bPRC) + { + // We change this script so we can setup permanent summons on/off. + // If you don't use this you may remove the next three lines. + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH); + SetLocalString(oCreature, "AI_ON_DEATH", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_ch_7_ondeath"); + } + // Initialize Associate modes for basic use. + ai_SetListeningPatterns(oCreature); + ai_SetNormalAppearance(oCreature); + ai_SetAssociateAIScript(oCreature, FALSE); + ai_SetAura(oCreature); + if(GetLocalInt(GetModule(), AI_RULE_PARTY_SCALE)) ai_CheckXPPartyScale(oCreature); + // Bioware summoned shadows are not incorporeal, also set the ai code. + if (GetTag(OBJECT_SELF) == "NW_S_SHADOW") + { + SetLocalInt(OBJECT_SELF, "X2_L_IS_INCORPOREAL", TRUE); + SetLocalString(OBJECT_SELF, AI_DEFAULT_SCRIPT, "ai_shadow"); + } +} +void ai_CheckPCStart(object oPC = OBJECT_INVALID) +{ + if(oPC == OBJECT_INVALID) oPC = GetFirstPC(); + // There should always be a PC widget. If it doesn't exist then we assume + // that the module is being loaded or started. + if(!NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)) + { + object oModule = GetModule(); + // Do PRC check and save variable to the module. + if(ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) != "") + SetLocalInt(oModule, AI_USING_PRC, TRUE); + ai_SetAIRules(); + ai_CheckAssociateData(oPC, oPC, "pc"); + ai_StartupPlugins(oPC); + ai_SetupPlayerTarget(oPC); + ai_SetupModuleGUIEvents(oPC); + ai_CreateWidgetNUI(oPC, oPC); + ai_SetNormalAppearance(oPC); + } +} +void ai_CopyMonster(object oCreature, object oModule) +{ + // After setting the monster lets see if we should copy it. + float fMonsterIncrease = GetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS); + if(GetIsEncounterCreature(oCreature) && fMonsterIncrease > 0.0) + { + int nMonsterIncrease; + float fMonsterCounter = GetLocalFloat(oModule, "AI_MONSTER_COUNTER"); + fMonsterCounter += fMonsterIncrease; + nMonsterIncrease = FloatToInt(fMonsterCounter); + if(nMonsterIncrease > 0) + { + fMonsterCounter = fMonsterCounter - IntToFloat(nMonsterIncrease); + } + SetLocalFloat(oModule, "AI_MONSTER_COUNTER", fMonsterCounter); + while(nMonsterIncrease > 0) + { + CopyObject(oCreature, GetLocation(oCreature), OBJECT_INVALID, "", TRUE); + nMonsterIncrease = nMonsterIncrease - 1; + } + } +} +void ai_CreateMonster(json jCreature, location lLocation, object oModule) +{ + //WriteTimestampedLogEntry("0i_module, 181, " + JsonDump(jCreature, 1)); + object oCreature = JsonToObject(jCreature, lLocation, OBJECT_INVALID, TRUE); + // Lets set the new version as spawned so we skip the initial setup again. + SetLocalInt(oCreature, AI_ONSPAWN_EVENT, TRUE); + /*if(GetLocalInt(oModule, AI_RULE_CORPSES_STAY)) + { + SetIsDestroyable(FALSE, FALSE, TRUE, oCreature); + SetLootable(oCreature, TRUE); + } */ + if(AI_DEBUG) ai_Debug("0i_module", "187", GetName(oCreature)); + ai_CopyMonster(oCreature, oModule); + return; +} +json ai_SetCompanionSummoning(object oCreature, json jCreature) +{ + if(GetHasFeat(FEAT_SUMMON_FAMILIAR, oCreature, TRUE)) + { + json jFamiliar = JsonObjectGet(jCreature, "FamiliarName"); + jFamiliar = JsonObjectSet(jFamiliar, "value", JsonString("Summoned Familiar")); + jCreature = JsonObjectSet(jCreature, "FamiliarName", jFamiliar); + jFamiliar = JsonObjectGet(jCreature, "FamiliarType"); + jFamiliar = JsonObjectSet(jFamiliar, "value", JsonInt(Random(11))); + return JsonObjectSet(jCreature, "FamiliarType", jFamiliar); + } + if(GetHasFeat(FEAT_ANIMAL_COMPANION , oCreature, TRUE)) + { + json jCompanion = JsonObjectGet(jCreature, "CompanionName"); + jCompanion = JsonObjectSet(jCompanion, "value", JsonString("Summoned Companion")); + jCreature = JsonObjectSet(jCreature, "CompanionName", jCompanion); + jCompanion = JsonObjectGet(jCreature, "CompanionType"); + jCompanion = JsonObjectSet(jCompanion, "value", JsonInt(Random(9))); + return JsonObjectSet(jCreature, "CompanionType", jCompanion); + } + return jCreature; +} +int ai_ChangeMonster(object oCreature, object oModule) +{ + object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, oCreature); + // Lets not mess up the cutscenes with silly RULES. + if(GetCutsceneMode(oPC)) return FALSE; + //float fDistance = GetDistanceBetween(oCreature, oPC); + // Looks bad to see creatures wink in and out plus could cause module errors. + //if(fDistance != 0.0 && fDistance < AI_RANGE_PERCEPTION) return oCreature; + if(IsInConversation(oCreature)) return FALSE; + json jCreature = ObjectToJson(oCreature, TRUE); + // We now use plugins to mod our monsters. + json jMonsterMods = GetLocalJson(oModule, AI_MONSTER_MOD_JSON); + if(JsonGetType(jMonsterMods) != JSON_TYPE_NULL) + { + SetLocalJson(oModule, AI_MONSTER_JSON, jCreature); + SetLocalObject(oModule, AI_MONSTER_OBJECT, oCreature); + int nIndex; + string sMonsterMod = JsonGetString(JsonArrayGet(jMonsterMods, nIndex)); + while(sMonsterMod != "") + { + ExecuteScript(sMonsterMod, oPC); + sMonsterMod = JsonGetString(JsonArrayGet(jMonsterMods, ++nIndex)); + } + jCreature = GetLocalJson(oModule, AI_MONSTER_JSON); + } + int nSummon = GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS) && + (GetHasFeat(FEAT_SUMMON_FAMILIAR, oCreature, TRUE)) || + GetHasFeat(FEAT_ANIMAL_COMPANION, oCreature, TRUE); + int nPercDist = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE) != 11 && + GetReputation(oCreature, oPC) < 11; + //WriteTimestampedLogEntry(GetName(oCreature) + ": fDistance: " + FloatToString(fDistance, 0, 2) + " nSummon: " + IntToString(nSummon) + + // " nPercDist: " + IntToString(nPercDist) + " Reputation: " + IntToString(GetReputation(oCreature, oPC))); + if(nSummon || nPercDist) + { + location lLocation = GetLocation(oCreature); + if(nPercDist) + { + json jPerception = JsonObjectGet(jCreature, "PerceptionRange"); + jPerception = JsonObjectSet(jPerception, "value", JsonInt(GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE))); + jCreature = JsonObjectSet(jCreature, "PerceptionRange", jPerception); + } + if(nSummon) jCreature = ai_SetCompanionSummoning(oCreature, jCreature); + SetLocalInt(oModule, AI_MONSTER_CHANGED, TRUE); + } + if(GetLocalInt(oModule, AI_MONSTER_CHANGED)) + { + SetIsDestroyable(TRUE, FALSE, FALSE, oCreature); + location lLocation = GetLocation(oCreature); + DestroyObject(oCreature); + AssignCommand(oModule, DelayCommand(1.0, ai_CreateMonster(jCreature, lLocation, oModule))); + DeleteLocalInt(oModule, AI_MONSTER_CHANGED); + return TRUE; + } + else ai_CopyMonster(oCreature, oModule); + DeleteLocalJson(oModule, AI_MONSTER_JSON); + DeleteLocalObject(oModule, AI_MONSTER_OBJECT); + return FALSE; +} +// Special event scripts for Infinite Dungeons! +void ai_SetIDMonsterEventScripts(object oCreature) +{ + //if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts."); + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + SetLocalString(oCreature, "AI_ON_HEARTBEAT", sScript); + if(sScript == "x2_def_heartbeat") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else if(sScript == "nw_c2_default1") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_HEARTBEAT SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Perception ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE); + SetLocalString(oCreature, "AI_ON_NOTICE", sScript); + if(sScript == "x2_def_percept") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_id_events"); + else if(sScript == "nw_c2_default2") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_NOTICE SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On End Combat Round ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + SetLocalString(oCreature, "AI_ON_END_COMBATROUND", sScript); + if(sScript == "x2_def_endcombat") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_id_events"); + else if(sScript == "nw_c2_default3") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_END_COMBATROUND SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Dialogue ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + SetLocalString(oCreature, "AI_ON_DIALOGUE", sScript); + if(sScript == "x2_def_onconv") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_id_events"); + else if(sScript == "nw_c2_default4") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DIALOGUE_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Melee Attacked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + SetLocalString(oCreature, "AI_ON_MELEE_ATTACKED", sScript); + if(sScript == "x2_def_attacked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_id_events"); + else if(sScript == "nw_c2_default5") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_MELEE_ATTACKED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Damaged ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + SetLocalString(oCreature, "AI_ON_DAMAGED", sScript); + if(sScript == "x2_def_ondamage") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_id_events"); + else if(sScript == "nw_c2_default6") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DAMAGED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + // We don't set OnDeath for Infinite Dungeons! + //********** On Death ********** + //sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH); + //SetLocalString(oCreature, "AI_ON_DEATH", sScript); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_id_events"); + //********** On Disturbed ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + SetLocalString(oCreature, "AI_ON_DISTURBED", sScript); + if(sScript == "x2_def_ondisturb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_id_events"); + else if(sScript == "nw_c2_default8") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DISTURBED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //********** On Rested ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED); + SetLocalString(oCreature, "AI_ON_RESTED", sScript); + if(sScript == "x2_def_rested") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_id_events"); + else if(sScript == "nw_c2_defaulta") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_RESTED SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Spell Cast At ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + SetLocalString(oCreature, "AI_ON_SPELLCASTAT", sScript); + if(sScript == "x2_def_spellcast") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_id_events"); + else if(sScript == "nw_c2_defaultb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_SPELLCASTAT_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Blocked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + SetLocalString(oCreature, "AI_ON_BLOCKED_BY_DOOR", sScript); + if(sScript == "x2_def_onblocked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_id_events"); + else if(sScript == "nw_c2_defaulte") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_BLOCKED_BY_DOOR SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); +} +// Special event scripts for Infinite Dungeons with PRC! +void ai_SetPRCIDMonsterEventScripts(object oCreature) +{ + //if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts for PRC."); + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + SetLocalString(oCreature, "AI_ON_HEARTBEAT", sScript); + if(sScript == "x2_def_heartbeat") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_prc_id_events"); + else if(sScript == "nw_c2_default1") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_HEARTBEAT SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Perception ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE); + SetLocalString(oCreature, "AI_ON_NOTICE", sScript); + if(sScript == "x2_def_percept") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_prc_id_events"); + else if(sScript == "nw_c2_default2") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_NOTICE SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On End Combat Round ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + SetLocalString(oCreature, "AI_ON_END_COMBATROUND", sScript); + if(sScript == "x2_def_endcombat") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_prc_id_events"); + else if(sScript == "nw_c2_default3") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_END_COMBATROUND SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Dialogue ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + SetLocalString(oCreature, "AI_ON_DIALOGUE", sScript); + if(sScript == "x2_def_onconv") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_prc_id_events"); + else if(sScript == "nw_c2_default4") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DIALOGUE_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Melee Attacked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + SetLocalString(oCreature, "AI_ON_MELEE_ATTACKED", sScript); + if(sScript == "x2_def_attacked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_prc_id_events"); + else if(sScript == "nw_c2_default5") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_MELEE_ATTACKED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Damaged ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + SetLocalString(oCreature, "AI_ON_DAMAGED", sScript); + if(sScript == "x2_def_ondamage") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_prc_id_events"); + else if(sScript == "nw_c2_default6") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DAMAGED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + // We don't set OnDeath for PRC or Infinite dungeons. + //********** On Death ********** + //sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH); + //SetLocalString(oCreature, "AI_ON_DEATH", sScript); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_prc_id_events"); + //********** On Disturbed ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + SetLocalString(oCreature, "AI_ON_DISTURBED", sScript); + if(sScript == "x2_def_ondisturb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_prc_id_events"); + else if(sScript == "nw_c2_default8") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_DISTURBED_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //********** On Rested ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED); + SetLocalString(oCreature, "AI_ON_RESTED", sScript); + if(sScript == "x2_def_rested") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_prc_id_events"); + else if(sScript == "nw_c2_defaulta") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_RESTED SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Spell Cast At ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + SetLocalString(oCreature, "AI_ON_SPELLCASTAT", sScript); + if(sScript == "x2_def_spellcast") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_prc_id_events"); + else if(sScript == "nw_c2_defaultb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_SPELLCASTAT_SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //********** On Blocked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + SetLocalString(oCreature, "AI_ON_BLOCKED_BY_DOOR", sScript); + if(sScript == "x2_def_onblocked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_prc_id_events"); + else if(sScript == "nw_c2_defaulte") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_prc_id_events"); + else if(sScript == "") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_id_events"); + else WriteTimestampedLogEntry("ON_BLOCKED_BY_DOOR SCRIPT ERROR: AI did not capture " + sScript + " script for " + GetName(oCreature) + "."); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); +} +// Special event scripts for PRC associates! +void ai_SetPRCAssociateEventScripts(object oCreature) +{ + //if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts for PRC."); + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + SetLocalString(oCreature, "AI_ON_HEARTBEAT", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac1") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "0e_prc_ch_events"); + //********** On Perception ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE); + SetLocalString(oCreature, "AI_ON_NOTICE", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac2") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "0e_prc_ch_events"); + //********** On End Combat Round ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + SetLocalString(oCreature, "AI_ON_END_COMBATROUND", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac3") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "0e_prc_ch_events"); + //********** On Dialogue ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + SetLocalString(oCreature, "AI_ON_DIALOGUE", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac4") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "0e_prc_ch_events"); + //********** On Melee Attacked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + SetLocalString(oCreature, "AI_ON_MELEE_ATTACKED", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac5") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "0e_prc_ch_events"); + //********** On Damaged ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + SetLocalString(oCreature, "AI_ON_DAMAGED", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac6") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "0e_prc_ch_events"); + //********** On Disturbed ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + SetLocalString(oCreature, "AI_ON_DISTURBED", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ac8") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "0e_prc_ch_events"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //********** On Rested ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED); + SetLocalString(oCreature, "AI_ON_RESTED", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_prc_ch_events"); + else if(sScript == "nw_ch_aca") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "0e_prc_ch_events"); + //********** On Spell Cast At ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + SetLocalString(oCreature, "AI_ON_SPELLCASTAT", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_prc_ch_events"); + else if(sScript == "nw_ch_acb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "0e_prc_ch_events"); + //********** On Blocked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + SetLocalString(oCreature, "AI_ON_BLOCKED_BY_DOOR", sScript); + if(sScript == "default") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_prc_ch_events"); + else if(sScript == "nw_ch_ace") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "0e_prc_ch_events"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); + if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature); +} +void ai_ChangeEventScriptsForMonster(object oCreature) +{ + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + if(sScript == "0e_c2_1_hb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_c2_default1"); + //********** On Perception ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE); + if(sScript == "0e_c2_2_percept") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_c2_default2"); + //********** On End Combat Round ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + if(sScript == "0e_c2_3_endround") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_c2_default3"); + //********** On Dialogue ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + if(sScript == "0e_c2_4_convers") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "nw_c2_default4"); + //********** On Melee Attacked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + if(sScript == "0e_c2_5_phyatked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "nw_c2_default5"); + //********** On Damaged ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + if(sScript == "0e_c2_6_damaged") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "nw_c2_default6"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "nw_c2_deafult7"); + //********** On Disturbed ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + if(sScript == "0e_c2_8_disturb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "nw_c2_default8"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "nw_c2_defaulta"); + //********** On Spell Cast At ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + if(sScript == "0e_c2_b_castat") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "nw_c2_defaultb"); + //********** On Blocked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + if(sScript == "0e_c2_e_blocked") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "nw_c2_defaulte"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "nw_c2_defaulte"); +} +void ai_ChangeEventScriptsForAssociate(object oCreature) +{ + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_ch_ac1"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_ch_ac2"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_ch_ac3"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "nw_ch_ac4"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "nw_ch_ac5"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "nw_ch_ac6"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "nw_ch_ac7"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "nw_ch_ac8"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "nw_ch_aca"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "nw_ch_acb"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "nw_ch_ace"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "nw_ch_acd"); +} diff --git a/src/module/nss/0i_nui.nss b/src/module/nss/0i_nui.nss new file mode 100644 index 0000000..eab5ee7 --- /dev/null +++ b/src/module/nss/0i_nui.nss @@ -0,0 +1,434 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_nui +//////////////////////////////////////////////////////////////////////////////// + Include script for handling window displays. + + Use the following to get/set window information. + string sBind = NuiGetNthBind (oPlayer, nToken, FALSE, #); + json jMenuInfo = NuiGetBind (oPlayer, nToken, sBind); + # Gets json information for window : + 0 - string - "window_title" + 1 - json - "window_geometry" : "h", "w", "x", "y" + 2 - bool - "window_resizable" + 3 - bool - "window_closable" + 4 - bool - "window_transparent" + 5 - bool - "window_border" + + Layout pixel sizes: + Pixel height Title bar 33. + Pixel height Top border 10, between widgets 8, bottom border 10. + Pixel width Left border 10, between widgets 4, right border 10. + + Group outer lines add 12 to the vertical and horizontal lines. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +#include "nw_inc_nui" +struct stComboBox +{ + json jIndex; + json jCombo; + json jRow; + json jResRefArray; + json jWinArray; + json jCanSummon; // Index of all the summons in summons.2da +}; + +// Saves the menu to the campaign database. +void SaveMenuToCampaignDb(object oPC, int nToken, string sWndId); +// Returns the middle of the screen for the x position. +// oPC using the menu. +// fMenuWidth - the width of the menu to display. +float GetGUIWidthMiddle(object oPC, float fMenuWidth); + +// Returns the middle of the screen for the y position. +// oPC using the menu. +// fMenuHeight - the height of the menu to display. +float GetGUIHeightMiddle(object oPC, float fMenuHeight); + +// Checks to see if sWndId is open. +// If the window is open it removes it and returns FALSE +// If the window is closed it returns TRUE +int IsWindowClosed(object oPC, string sWndId); + +// Returns the Window ID (nToken). +// oPC is the PC using the menu. +// jLayout is the Layout of the menu. +// sWinID is the string ID for this window. +// sTitle is the Title of the menu. +// fX is the X position of the menu (-1.0: Centers, -2.0: UpperRight on Mouse, -3.0: Centers top of mouse). +// fY is the Y position of the menu (-1.0: Centers, -2.0: UpperRight on Mouse, -3.0: Centers top of mouse). +// fWidth is the width of the menu. +// fHeight is the height of the menu. +// bResize - TRUE will all it to be resized. +// bCollapse - TRUE will allow the window to be collapsable. +// bClose - TRUE will allow the window to be closed. +// bTransparent - TRUE makes the menu transparent. +// bBorder - TRUE makes the menu have a border. +// sEventScript will fire this event script for this window. +int SetWindow(object oPC, json jLayout, string sWinID, string sTitle, float fX, float fY, float fWidth, float fHeight, int bResize, int bCollapse, int bClose, int bTransparent, int bBorder, string sEventScript = ""); + +// Creates a label element in jRow. +// jRow is the row the label goes into. +// sLabel is the text placed in the label. +// If "" is passed then it will create a bind of sId + "_label". +// fWidth is the width of the label. +// fHeight is the Height of the label. +// nHAlign is horizonal align [NUI_HALING_*]. +// nVAlign is vertial align [NUI_VALING_*]. +// sId is the bind the event uses sId + "_event". +// sTooltip is the tooltip bind value. +json CreateLabel(json jRow, string sLabel, string sId, float fWidth, float fHeight, int nHAlign = 0, int nVAlign = 0, float fMargin = -1.0, string sTooltip = ""); + +// Creates a basic button element in jRow. +// jRow is the row the label goes into. +// sLabel is the text placed in the button. If "" is passed then it will +// create a bind of sId + "_label". +// sId is the binds for the button and the event uses sId + "_event". +// fWidth is the width of the button. +// fHeight is the Height of the button. +// fMargin is the space around the button. +// sTooltip is the tooltip bind value. +json CreateButton(json jRow, string sLabel, string sId, float fWidth, float fHeight, float fMargin = -1.0, string sTooltip = ""); + +// Creates a basic button select element in jRow. +// jRow is the row the label goes into. +// sLabel is the text placed in the button. If "" is passed then it will +// create a bind of sId + "_label". +// sId is the binds for the button and the event uses sId + "_event". +// fWidth is the width of the button. +// fHeight is the Height of the button. +// sTooltip is the tooltip bind value. +json CreateButtonSelect(json jRow, string sLabel, string sId, float fWidth, float fHeight, string sToolTip = ""); + +// Creates a button element with an image in jRow. +// jRow is the row the label goes into. +// sImage is the resref of the image to use. +// If "" is passed then it will create a bind of sId + "_image". +// sId is the binds for the button and the event uses sId + "_event". +// fWidth is the width of the button. +// fHeight is the Height of the button. +// fMargin is the space around the button. +// sTooltip is the tooltip bind value. +json CreateButtonImage(json jRow, string sResRef, string sId, float fWidth, float fHeight, float fMargin = -1.0, string sTooltip = ""); + +// Creates a basic text box that is not editable element in jRow. +// jRow is the row the TextEdit box goes into. +// sId is the bind variable so we can change the text. +// fWidth the width of the box. +// fHeight the height of the box. +// bBorder will add border TRUE or remove it FALSE. +// nScroll use NUI_SCROLLBARS_* +// sTooltip is the tooltip bind value. +json CreateTextBox(json jRow, string sId, float fWidth, float fHeight, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO, string sTooltip = ""); + +// Creates a basic text edit box element in jRow. +// jRow is the row the TextEdit box goes into. +// sPlaceHolderBind is the bind for Placeholder. +// sValueBind is the bind variable so we can change the text. +// nMaxLength is the maximum lenght of the text (1 - 65535) +// bMultiline - True or False that is has multiple lines. +// fWidth the width of the box. +// fHeight the height of the box. +// sTooltip is the tooltip bind value. +json CreateTextEditBox(json jRow, string sPlaceHolderBind, string sValueBind, int nMaxLength, int bMultiline, float fWidth, float fHeight, string sToolTip = ""); + +// Creates a combo box element in jRow. +// jRow is the row the combo goes into. +// jCombo is the elements/list for the combo box. Use NuiComboEntry to add. +// sId is the binds for the combo and the event uses sId + "_event" +// sId + "_selected" is the bind for the selection in the combo box. +// fWidth is the width of the combo. +// fHeight is the Height of the combo. +// sTooltip is the tooltip bind value. +json CreateCombo(json jRow, json jCombo, string sId, float fWidth, float fHeight, string sToolTip = ""); + +// Creates an image element in jRow. +// jRow is the row the Image goes into. +// sImage is the resref of the image to use. If "" is passed then it will +// create a bind of sId + "_image". +// nAspect is the aspect of the image NUI_ASPECT_*. +// nHAlign is the horizontal alignment of the image NUI_HALIGN_*. +// nVAlign is the vertical alignment of the image NUI_VALIGN_*. +// fWidth the width of the box. +// fHeight the height of the box. +// sTooltip is the tooltip bind value. +json CreateImage(json jRow, string sResRef, string sId, int nAspect, int nHAlign, int nVAlign, float fWidth, float fHeight, float fMargin = -1.0, string sToolTip = ""); + +// Creates a check box element in jRow. +// jRow is the row the Checkbox box goes into. +// sLabel is the text placed in the label. +// If "" is passed then it will create a bind of sId + "_label". +// sId is the bind variable so we can change the text. +// sId + "_check" is the Bind:bool for if it is checked or not. +// fWidth is the width of the label. +// fHeight is the Height of the label. +// sTooltip is the tooltip bind value. +json CreateCheckBox(json jRow, string sLabel, string sId, float fWidth, float fHeight, string sToolTip = ""); + +// Creates a slider (Int based) element in jRow +// jRow is the row the Check box goes into. +// sId is the bind name. +// The binds are as follows. +// Value: sId + "_value" +// Minimum: sId + "_min" +// Maximum: sId + "_max" +// Step size: sId + "_stepsize" +// fWidth is the width of the slider. +// fHeight is the Height of the slider. +// sTooltip is the tooltip bind value. +json CreateSlider(json jRow, string sId, float fWidth, float fHeight, string sToolTip = ""); + +// Creates an Options element in jRow. +// jRow is the row the Options will start on. +// sId is the bind name. +// The binds are as follows: +// Value: sId + "_value" +// Event is sId + "_event" +// nDirection: NUI_DIRECTION_* +// fWidth is the width of the options labels. +// fHeight is the height of the options labels. +// sTooltip is the tooltip bind value. +json CreateOptions(json jRow, string sId, int nDirection, json jLabels, float fWidth, float fHeight, string sToolTip = ""); + +// Creates a list element in jRow. +// jRow is the row the list will start on. +// jElements is the list of elements in the list. Use NuiListTemplateCell to add. +// sId is the bind name. +// The binds are Event is sId + "_event". +// Row count is bound to sId + "_count". +// fRowHeight is the height of the rendered rows. +// fWidth is the width of the options labels. +// fHeight is the height of the options labels. +// sTooltip is the tooltip bind value. +json CreateList(json jRow, json jElements, string sId, float fRowHeight, float fWidth, float fHeight, string sTooltip = ""); + +// Placed here temporarily until we can clean up our includes! +void ai_SetDMWAccessButton(int nButton, int bOn = TRUE); +int ai_GetDMWAccessButton(int nButton); +void ai_SetDMAIAccessButton(int nButton, int bOn = TRUE); +int ai_GetDMAIAccessButton(int nButton); + +void SaveMenuToCampaignDb(object oPC, int nToken, string sWndId) +{ + json jGeometry = NuiGetBind(oPC, nToken, "window_geometry"); + float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); + float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); + string sName = ai_RemoveIllegalCharacters(GetName(oPC)); + json jLocations = ai_GetCampaignDbJson("locations", sName, AI_DM_TABLE); + json jNUI = JsonObjectGet(jLocations, sWndId); + if(JsonGetType(jNUI) == JSON_TYPE_NULL) jNUI = JsonObject(); + jNUI = JsonObjectSet(jNUI, "x", JsonFloat(fX)); + jNUI = JsonObjectSet(jNUI, "y", JsonFloat(fY)); + jLocations = JsonObjectSet(jLocations, sWndId, jNUI); + ai_SetCampaignDbJson("locations", jLocations, sName, AI_DM_TABLE); +} + +float GetGUIWidthMiddle(object oPC, float fMenuWidth) +{ + // Get players window information. + float fGUI_Width = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_WIDTH)); + float fGUI_Scale = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0; + fMenuWidth = fMenuWidth * fGUI_Scale; + return (fGUI_Width / 2.0) - (fMenuWidth / 2.0); +} +float GetGUIHeightMiddle(object oPC, float fMenuHeight) +{ + // Get players window information. + float fGUI_Height = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_HEIGHT)); + float fGUI_Scale = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0; + fMenuHeight = fMenuHeight * fGUI_Scale; + return (fGUI_Height / 2.0) - (fMenuHeight / 2.0); +} +int IsWindowClosed(object oPC, string sWndId) +{ + int nToken = NuiFindWindow(oPC, sWndId); + if(nToken) + { + NuiDestroy(oPC, nToken); + return FALSE; + } + return TRUE; +} +int SetWindow(object oPC, json jLayout, string sWinID, string sTitle, float fX, float fY, float fWidth, float fHeight, int bResize, int bCollapse, int bClose, int bTransparent, int bBorder, string sEventScript = "") +{ + json jWindow; + if (bCollapse) jWindow = NuiWindow (jLayout, NuiBind ("window_title"), NuiBind ("window_geometry"), + NuiBind ("window_resizable"), JsonNull (), NuiBind ("window_closable"), + NuiBind ("window_transparent"), NuiBind ("window_border")); + + else jWindow = NuiWindow (jLayout, NuiBind ("window_title"), NuiBind ("window_geometry"), + NuiBind ("window_resizable"), JsonBool (FALSE), NuiBind ("window_closable"), + NuiBind ("window_transparent"), NuiBind ("window_border")); + + int nToken = NuiCreate (oPC, jWindow, sWinID, sEventScript); + if(!bCollapse && !bClose && !bBorder) NuiSetBind (oPC, nToken, "window_title", JsonBool (FALSE)); + else NuiSetBind (oPC, nToken, "window_title", JsonString (sTitle)); + if (fX == -1.0) fX = GetGUIWidthMiddle (oPC, fWidth); + if (fY == -1.0) fY = GetGUIHeightMiddle (oPC, fHeight); + int nScale = GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE); + if(nScale != 100) + { + fHeight = fHeight * (IntToFloat(1050 - nScale) / 1000.0); + fWidth = fWidth * (IntToFloat(1200 - nScale) / 1000.0); + } + NuiSetBind (oPC, nToken, "window_geometry", NuiRect (fX, + fY, fWidth, fHeight)); + NuiSetBind (oPC, nToken, "window_resizable", JsonBool (bResize)); + NuiSetBind (oPC, nToken, "window_closable", JsonBool (bClose)); + NuiSetBind (oPC, nToken, "window_transparent", JsonBool (bTransparent)); + NuiSetBind (oPC, nToken, "window_border", JsonBool (bBorder)); + return nToken; +} +json CreateLabel(json jRow, string sLabel, string sId, float fWidth, float fHeight, int nHAlign = 0, int nVAlign = 0, float fMargin = -1.0, string sTooltip = "") +{ + json jLabel; + if(sLabel == "") jLabel = NuiId(NuiLabel(NuiBind(sId + "_label"), JsonInt(nHAlign), JsonInt(nVAlign)), sId); + else jLabel = NuiId(NuiLabel(JsonString(sLabel), JsonInt(nHAlign), JsonInt(nVAlign)), sId); + jLabel = NuiWidth(jLabel, fWidth); + jLabel = NuiHeight(jLabel, fHeight); + if (fMargin > -1.0) jLabel = NuiMargin(jLabel, fMargin); + if(sTooltip != "") jLabel = NuiTooltip (jLabel, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jLabel); +} +json CreateButton(json jRow, string sLabel, string sId, float fWidth, float fHeight, float fMargin = -1.0, string sTooltip = "") +{ + json jButton; + if(sLabel == "") jButton = NuiEnabled(NuiId(NuiButton(NuiBind (sId + "_label")), sId), NuiBind(sId + "_event")); + else jButton = NuiEnabled(NuiId(NuiButton(JsonString(sLabel)), sId), NuiBind(sId + "_event")); + jButton = NuiWidth(jButton, fWidth); + jButton = NuiHeight(jButton, fHeight); + if (fMargin > -1.0) jButton = NuiMargin(jButton, fMargin); + if (sTooltip != "") jButton = NuiTooltip(jButton, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jButton); +} +json CreateButtonSelect(json jRow, string sLabel, string sId, float fWidth, float fHeight, string sTooltip = "") +{ + json jButton; + if(sLabel == "") jButton = NuiEnabled(NuiId(NuiButtonSelect(NuiBind (sId + "_label"), NuiBind(sId)), sId), NuiBind(sId + "_event")); + else jButton = NuiEnabled(NuiId(NuiButtonSelect(JsonString(sLabel), NuiBind(sId)), sId), NuiBind(sId + "_event")); + jButton = NuiWidth(jButton, fWidth); + jButton = NuiHeight(jButton, fHeight); + if(sTooltip != "") jButton = NuiTooltip(jButton, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jButton); +} +json CreateButtonImage(json jRow, string sResRef, string sId, float fWidth, float fHeight, float fMargin = -1.0, string sTooltip = "") +{ + json jButton; + if(sResRef == "") jButton = NuiEnabled(NuiId (NuiButtonImage(NuiBind(sId + "_image")), sId), NuiBind(sId + "_event")); + else jButton = NuiEnabled(NuiId(NuiButtonImage(JsonString(sResRef)), sId), NuiBind(sId + "_event")); + jButton = NuiWidth(jButton, fWidth); + jButton = NuiHeight(jButton, fHeight); + if(fMargin > -1.0) jButton = NuiMargin(jButton, fMargin); + if(sTooltip != "") jButton = NuiTooltip(jButton, NuiBind (sTooltip)); + jButton = NuiEncouraged(jButton, NuiBind(sId + "_encouraged")); + return JsonArrayInsert(jRow, jButton); +} +json CreateTextBox(json jRow, string sId, float fWidth, float fHeight, int bBorder = TRUE, int nScroll = NUI_SCROLLBARS_AUTO, string sTooltip = "") +{ + json jTextBox = NuiEnabled(NuiText(NuiBind(sId), bBorder, nScroll), NuiBind(sId + "_event")); + jTextBox = NuiWidth(jTextBox, fWidth); + jTextBox = NuiHeight(jTextBox, fHeight); + if(sTooltip != "") jTextBox = NuiTooltip(jTextBox, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, JsonObjectSet(jTextBox, "text_color", NuiColor (255, 0, 0))); +} +json CreateTextEditBox(json jRow, string sPlaceHolderBind, string sValueBind, int nMaxLength, int bMultiline, float fWidth, float fHeight, string sTooltip = "") +{ + json jObject = NuiEnabled(NuiTextEdit(NuiBind(sPlaceHolderBind), NuiBind(sValueBind), nMaxLength, bMultiline), NuiBind(sValueBind + "_event")); + jObject = NuiWidth(jObject, fWidth); + jObject = NuiHeight(jObject, fHeight); + if(sTooltip != "") jObject = NuiTooltip(jObject, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jObject); +} +json CreateCombo(json jRow, json jList, string sId, float fWidth, float fHeight, string sTooltip = "") +{ + json jCombo; + if(JsonGetType(jList) == JSON_TYPE_NULL) + { + jCombo = NuiId(NuiCombo(NuiBind(sId + "_list"), NuiBind(sId + "_selected")), sId + "_event"); + } + jCombo = NuiId(NuiCombo(jList, NuiBind (sId + "_selected")), sId); + jCombo = NuiEnabled(jCombo, NuiBind (sId + "_event")); + jCombo = NuiWidth(jCombo, fWidth); + jCombo = NuiHeight(jCombo, fHeight); + if(sTooltip != "") jCombo = NuiTooltip(jCombo, NuiBind(sTooltip)); + return JsonArrayInsert(jRow, jCombo); +} +json CreateImage(json jRow, string sResRef, string sId, int nAspect, int nHAlign, int nVAlign, float fWidth, float fHeight, float fMargin = -1.0, string sTooltip = "") +{ + json jImage; + if(sResRef == "") jImage = NuiEnabled(NuiId(NuiImage(NuiBind(sId + "_image"), JsonInt(nAspect), JsonInt(nHAlign), JsonInt(nVAlign)), sId), NuiBind(sId + "_event")); + else jImage = NuiEnabled(NuiId(NuiImage(JsonString(sResRef), JsonInt(nAspect), JsonInt(nHAlign), JsonInt(nVAlign)), sId), NuiBind(sId + "_event")); + jImage = NuiWidth(jImage, fWidth); + jImage = NuiHeight(jImage, fHeight); + if (fMargin > -1.0) jImage = NuiMargin(jImage, fMargin); + if(sTooltip != "") jImage = NuiTooltip(jImage, NuiBind(sTooltip)); + return JsonArrayInsert(jRow, jImage); +} +json CreateCheckBox(json jRow, string sLabel, string sId, float fWidth, float fHeight, string sTooltip = "") +{ + json jCheckBox; + if(sLabel == "") jCheckBox = NuiEnabled(NuiId(NuiCheck(NuiBind(sId + "_label"), NuiBind(sId + "_check")), sId), NuiBind(sId + "_event")); + else jCheckBox = NuiEnabled(NuiId(NuiCheck(JsonString(sLabel), NuiBind(sId + "_check")), sId), NuiBind(sId + "_event")); + jCheckBox = NuiWidth(jCheckBox, fWidth); + jCheckBox = NuiHeight(jCheckBox, fHeight); + if (sTooltip != "") jCheckBox = NuiTooltip (jCheckBox, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jCheckBox); +} +json CreateSlider(json jRow, string sId, float fWidth, float fHeight, string sTooltip = "") +{ + json jSlider; + jSlider = NuiEnabled(NuiId(NuiSlider(NuiBind(sId + "_value"), NuiBind(sId + "_min"), NuiBind(sId + "_max"), NuiBind(sId + "_stepsize")), sId), NuiBind(sId + "_event")); + jSlider = NuiWidth(jSlider, fWidth); + jSlider = NuiHeight(jSlider, fHeight); + if(sTooltip != "") jSlider = NuiTooltip(jSlider, NuiBind(sTooltip)); + return JsonArrayInsert(jRow, jSlider); +} +json CreateOptions(json jRow, string sId, int nDirection, json jLabels, float fWidth, float fHeight, string sTooltip = "") +{ + json jOption; + jOption = NuiEnabled(NuiId(NuiOptions(nDirection, jLabels, NuiBind(sId + "_value")), sId), NuiBind(sId + "_event")); + jOption = NuiWidth(jOption, fWidth); + jOption = NuiHeight(jOption, fHeight); + if(sTooltip != "") jOption = NuiTooltip (jOption, NuiBind (sTooltip)); + return JsonArrayInsert(jRow, jOption); +} +json CreateList(json jRow, json jElements, string sId, float fRowHeight, float fWidth, float fHeight, string sTooltip = "") +{ + json jList; + jList = NuiId(NuiList(jElements, NuiBind(sId), fRowHeight), sId + "_id"); + jList = NuiWidth(jList, fWidth); + jList = NuiHeight(jList, fHeight); + if (sTooltip != "") jList = NuiTooltip(jList, NuiBind(sTooltip)); + return JsonArrayInsert(jRow, jList); +} +void ai_SetDMWAccessButton(int nButton, int bOn = TRUE) +{ + json jRules = ai_GetCampaignDbJson("rules"); + int nWidgetButtons = JsonGetInt(JsonObjectGet(jRules, sDMWidgetAccessVarname)); + if(bOn) nWidgetButtons = nWidgetButtons | nButton; + else nWidgetButtons = nWidgetButtons & ~nButton; + SetLocalInt(GetModule(), sDMWidgetAccessVarname, nWidgetButtons); + jRules = JsonObjectSet(jRules, sDMWidgetAccessVarname, JsonInt(nWidgetButtons)); + ai_SetCampaignDbJson("rules", jRules); +} +int ai_GetDMWAccessButton(int nButton) +{ + int nWidgetButtons = GetLocalInt(GetModule(), sDMWidgetAccessVarname); + return nWidgetButtons & nButton; +} +void ai_SetDMAIAccessButton(int nButton, int bOn = TRUE) +{ + json jRules = ai_GetCampaignDbJson("rules"); + int nWidgetButtons = JsonGetInt(JsonObjectGet(jRules, sDMAIAccessVarname)); + if(bOn) nWidgetButtons = nWidgetButtons | nButton; + else nWidgetButtons = nWidgetButtons & ~nButton; + SetLocalInt(GetModule(), sDMAIAccessVarname, nWidgetButtons); + jRules = JsonObjectSet(jRules, sDMAIAccessVarname, JsonInt(nWidgetButtons)); + ai_SetCampaignDbJson("rules", jRules); +} +int ai_GetDMAIAccessButton(int nButton) +{ + int nWidgetButtons = GetLocalInt(GetModule(), sDMAIAccessVarname); + return nWidgetButtons & nButton; +} + diff --git a/src/module/nss/0i_player_target.nss b/src/module/nss/0i_player_target.nss new file mode 100644 index 0000000..bed4834 --- /dev/null +++ b/src/module/nss/0i_player_target.nss @@ -0,0 +1,793 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_player_target +//////////////////////////////////////////////////////////////////////////////// + Include script for handling player targeting functions. + +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +#include "0i_menus" +// Setup an AI OnPlayerTarget Event script while allowing any module onplayer +// target event script to still work. +void ai_SetupPlayerTarget(object oCreature); +// Selects a target for oAssocite to follow. +void ai_AllSelectTarget(object oPC, object oAssociate, object oTarget); +// Removes the Cutscene ghosts and variables from all associates. For original AI scripts. +void ai_OriginalRemoveAllActionMode(object oPC); +// Removes the Cutscene ghosts and Command mode from all associates. +void ai_RemoveAllActionMode(object oPC); +// Once a trap has been selected from the associates inventory move to placing the trap. +void ai_SelectTrap(object oPC, object oAssociate, object oItem); +// Place the selected trap at the location selected by the player for OBJECT_SELF. +void ai_PlaceTrap(object oPC, location lLocation); +// Adds a creature to nGroup for oDM +void ai_AddToGroup(object oDM, object oTarget, string sTargetMode); +// Has nGroup perform an action based on the selected target or location. +void ai_DMAction(object oDM, object oTarget, location lLocation, string sTargetMode); +// Get oPC to select a spell target for oAssociate. +void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem); +// Updates oAssociates widget by destroying the current one and rebuilding. +void ai_UpdateAssociateWidget(object oPC, object oAssociate); +// Sets oAssociates action mode for nFeat from the quick widget menu +int ai_SetActionMode(object oAssociate, int nFeat); + +void ai_SetupPlayerTarget(object oCreature) +{ + object oModule = GetModule(); + string sModuleTargetEvent = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET); + if(sModuleTargetEvent != "") + { + if(sModuleTargetEvent != "0e_player_target") SetLocalString(oModule, AI_MODULE_TARGET_EVENT, sModuleTargetEvent); + } + SetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET, "0e_player_target"); +} +void ai_OriginalActionAssociate(object oPC, object oTarget, location lLocation) +{ + object oAssociate = OBJECT_SELF; + if(!GetLocalInt(oAssociate, sGhostModeVarname) && GetLocalInt(oPC, sGhostModeVarname)) + { + effect eGhost = EffectCutsceneGhost(); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oAssociate); + SetLocalInt(oAssociate, sGhostModeVarname, TRUE); + } + int nObjectType = GetObjectType(oTarget); + ai_ClearCreatureActions(TRUE); + if(oTarget == GetArea(oPC)) + { + ActionMoveToLocation(lLocation, TRUE); + if(GetLocalObject(oPC, AI_FOLLOW_TARGET) == oAssociate) + { + float fFollowDistance = 3.0; + AssignCommand(oPC, ai_ClearCreatureActions()); + AssignCommand(oPC, ActionForceFollowObject(oAssociate, fFollowDistance)); + } + } + else if(nObjectType == OBJECT_TYPE_CREATURE) + { + if(oTarget != GetLocalObject(oPC, AI_TARGET_ASSOCIATE)) + { + if(GetMaster(oTarget) == oPC) + { + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION"); + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oTarget); + ai_SendMessages(GetName(oTarget) + " is now in Action Mode.", AI_COLOR_YELLOW, oPC); + } + else ActionMoveToObject(oTarget, TRUE); + } + } + else if(nObjectType == OBJECT_TYPE_DOOR) + { + if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_DISARM_TRAPS, oAssociate)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) + { + bkAttemptToDisarmTrap(oTarget); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + } + if(GetLocked(oTarget)) bkAttemptToOpenLock(oTarget); + if(GetIsOpen(oTarget)) + { + ActionCloseDoor(oTarget, TRUE); + } + else ActionOpenDoor(oTarget, TRUE); + } + else if(nObjectType == OBJECT_TYPE_ITEM) + { + ActionPickUpItem(oTarget); + } + else if(nObjectType == OBJECT_TYPE_PLACEABLE) + { + ActionMoveToObject(oTarget, TRUE); + if(GetHasInventory(oTarget)) + { + if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) + { + bkAttemptToDisarmTrap(oTarget); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + if(GetLocked(oTarget)) + { + if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate)) + { + bkAttemptToOpenLock(oTarget); + } + else AssignCommand(oAssociate, ai_HaveCreatureSpeak(oAssociate, 0, "This " + GetName(oTarget) + " is locked!")); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE); + } + else if(GetLocked(oTarget)) + { + if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate)) + { + bkAttemptToOpenLock(oTarget); + } + else AssignCommand(oAssociate, ai_HaveCreatureSpeak(oAssociate, 0, "This " + GetName(oTarget) + " is locked!")); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE); + } + DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE); + } + else if(nObjectType == OBJECT_TYPE_TRIGGER) + { + if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) bkAttemptToDisarmTrap(oTarget); + } + } + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_OriginalActionAllAssociates(object oPC, object oTarget, location lLocation) +{ + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation)); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation)); + } +} +void ai_ActionAssociate(object oPC, object oTarget, location lLocation) +{ + object oAssociate = OBJECT_SELF; + if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && + !ai_GetAIMode(oAssociate, AI_MODE_GHOST) && + !GetLocalInt(oAssociate, sGhostModeVarname)) + { + effect eGhost = EffectCutsceneGhost(); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oAssociate); + SetLocalInt(oAssociate, sGhostModeVarname, TRUE); + } + int nObjectType = GetObjectType(oTarget); + ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, TRUE); + ai_ClearCreatureActions(TRUE); + if(oTarget == GetArea(oPC)) + { + ActionMoveToLocation(lLocation, TRUE); + if(GetLocalObject(oPC, AI_FOLLOW_TARGET) == oAssociate) + { + float fFollowDistance = ai_GetFollowDistance(oPC); + if(GetDistanceBetween(oAssociate, oPC) <= fFollowDistance) + { + DelayCommand(fFollowDistance, AssignCommand(oPC, ActionMoveToObject(oAssociate, TRUE, fFollowDistance))); + } + else AssignCommand(oPC, ActionMoveToObject(oAssociate, TRUE, fFollowDistance)); + } + } + else if(nObjectType == OBJECT_TYPE_CREATURE) + { + if(GetIsDead(oTarget)) + { + AssignCommand(oAssociate, ActionDoCommand(ai_SearchObject(oAssociate, oTarget, oPC, TRUE))); + } + else if(GetIsEnemy(oTarget, oAssociate)) + { + // Lock them into attacking this target only. + SetLocalObject(oAssociate, AI_PC_LOCKED_TARGET, oTarget); + // This resets a henchmens failed Moral save in combat. + if(GetLocalString(oAssociate, AI_COMBAT_SCRIPT) == "ai_coward") + { + SetLocalString(oAssociate, AI_COMBAT_SCRIPT, GetLocalString(oAssociate, AI_DEFAULT_SCRIPT)); + } + if(ai_GetIsInCombat(oAssociate)) ai_DoAssociateCombatRound(oAssociate, oTarget); + else + { + ai_HaveCreatureSpeak(oAssociate, 5, ":0:1:2:3:6:"); + ai_StartAssociateCombat(oAssociate, oTarget); + } + ai_SendMessages(GetName(oAssociate) + " is attacking " + GetName(oTarget), AI_COLOR_RED, oPC); + } + else + { + ActionMoveToObject(oTarget, TRUE); + // Player will be stuck with this variable if they are not using the AI. + DeleteLocalInt(oTarget, "AI_I_AM_BEING_HEALED"); + ActionDoCommand(ai_ActionTryHealing(oAssociate, oTarget)); + } + } + else if(nObjectType == OBJECT_TYPE_DOOR) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) + { + int bStopAction = !GetLocalInt(oTarget, "AI_CANNOT_TRAP_" + GetTag(oAssociate)); + if(ai_ReactToTrap(oAssociate, oTarget, TRUE)) bStopAction = TRUE; + if(bStopAction) + { + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + } + } + if(GetLocked(oTarget)) ai_AttemptToByPassLock(oAssociate, oTarget, TRUE); + else if(GetIsOpen(oTarget)) ActionCloseDoor(oTarget, TRUE); + else ActionOpenDoor(oTarget, TRUE); + } + else if(nObjectType == OBJECT_TYPE_ITEM) + { + ActionPickUpItem(oTarget); + } + else if(nObjectType == OBJECT_TYPE_PLACEABLE) + { + ActionMoveToObject(oTarget, TRUE); + if(GetHasInventory(oTarget)) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) + { + if(ai_ReactToTrap(oAssociate, oTarget, TRUE)) + { + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + + } + } + if(GetLocked(oTarget)) ai_AttemptToByPassLock(oAssociate, oTarget, TRUE); + else ActionDoCommand(ai_SearchObject(oAssociate, oTarget, oPC, TRUE)); + } + else + { + if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) + { + AssignCommand(oAssociate, ai_ClearCreatureActions()); + // Check to make sure we are using a melee weapon. + if(ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oAssociate)) || + ai_EquipBestMeleeWeapon(oAssociate)) + { + AssignCommand(oAssociate, ActionWait(1.0)); + AssignCommand(oAssociate, ActionAttack(oTarget)); + } + } + else AssignCommand(oAssociate, DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE)); + } + } + else if(nObjectType == OBJECT_TYPE_TRIGGER) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate); + if(GetTrapDetectedBy(oTarget, oAssociate)) ai_ReactToTrap(oAssociate, oTarget, TRUE); + } + } + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_ActionAllAssociates(object oPC, object oTarget, location lLocation) +{ + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation)); + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation)); + } +} +void ai_SelectFollowTarget(object oPC, object oAssociate, object oTarget) +{ + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + int nToken = NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI); + float fRange = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + + StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate))); + string sRange = FloatToString(fRange, 0, 0); + if(oAssociate == oTarget) + { + ai_SetAIMode(oAssociate, AI_MODE_FOLLOW, FALSE); + DeleteLocalObject(oAssociate, AI_FOLLOW_TARGET); + string sTarget; + if(ai_GetIsCharacter(oAssociate)) + { + sTarget = "nobody"; + ai_SendMessages(GetName(oAssociate) + " is not following anyone now!", AI_COLOR_YELLOW, oPC); + } + else + { + sTarget = GetName(oPC); + ai_SendMessages(GetName(oAssociate) + " is now following " + sTarget + "!", AI_COLOR_YELLOW, oPC); + } + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]"); + } + else + { + ai_SetAIMode(oAssociate, AI_MODE_FOLLOW, TRUE); + SetLocalObject(oAssociate, AI_FOLLOW_TARGET, oTarget); + ai_SendMessages(GetName(oAssociate) + " is now following " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + AssignCommand(oAssociate, ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oAssociate))); + ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + GetName(oTarget) + " [" + sRange + " meters]"); + } + aiSaveAssociateModesToDb(oPC, oAssociate); +} +void ai_OriginalRemoveAllActionMode(object oPC) +{ + if(!ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST)) return; + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID && + !ai_GetAIMode(oAssociate, AI_MODE_GHOST) && + GetLocalInt(oAssociate, sGhostModeVarname)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID && + !ai_GetAIMode(oAssociate, AI_MODE_GHOST) && + GetLocalInt(oAssociate, sGhostModeVarname)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + } +} +void ai_RemoveAllActionMode(object oPC) +{ + object oAssociate; + int nIndex; + for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) + { + ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE); + if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && + !ai_GetAIMode(oAssociate, AI_MODE_GHOST) && + GetLocalInt(oAssociate, sGhostModeVarname)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + ExecuteScript("nw_ch_ac1", oAssociate); + } + } + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) + { + ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE); + if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && + !ai_GetAIMode(oAssociate, AI_MODE_GHOST) && + GetLocalInt(oAssociate, sGhostModeVarname)) + { + ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST); + DeleteLocalInt(oAssociate, sGhostModeVarname); + } + ExecuteScript("nw_ch_ac1", oAssociate); + } + } +} +void ai_SelectTrap(object oPC, object oAssociate, object oItem) +{ + if(GetBaseItemType(oItem) != BASE_ITEM_TRAPKIT) + { + ai_SendMessages("A trap kit was not selected.", AI_COLOR_YELLOW, oPC); + return; + } + ai_SendMessages("Now select a location to place the trap.", AI_COLOR_YELLOW, oPC); + SetLocalObject(oAssociate, "AI_TRAP_KIT", oItem); + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_PLACE_TRAP"); + OpenInventory(oAssociate, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_TILE, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_PlaceTrap(object oPC, location lLocation) +{ + object oItem = GetLocalObject(OBJECT_SELF, "AI_TRAP_KIT"); + itemproperty ipTrap = GetFirstItemProperty(oItem); + if(GetItemPropertyType(ipTrap) == ITEM_PROPERTY_TRAP) + { + ActionUseItemAtLocation(oItem, ipTrap, lLocation); + } + else ai_SendMessages("This trap kit does not have a trap property!", AI_COLOR_YELLOW, oPC); +} +void ai_AddToGroup(object oDM, object oTarget, string sTargetMode) +{ + string sGroup = GetStringRight(sTargetMode, 1); + if(oDM == oTarget) + { + ai_SendMessages("Group " + sGroup + " has been cleared.", AI_COLOR_YELLOW, oDM); + string sText = "Group " + sGroup; + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText + " (Left Action/Right Add)")); + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_COMMAND_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText + " (Left Action/Right Add)")); + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_COMMAND_NUI), "btn_cmd_group" + sGroup + "_label", JsonString(sText)); + DeleteLocalJson(oDM, "DM_GROUP" + sGroup); + return; + } + string sName = GetName(oTarget); + json jGroup = GetLocalJson(oDM, "DM_GROUP" + sGroup); + if(JsonGetType(jGroup) == JSON_TYPE_NULL) + { + string sText = sName + "'s group"; + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText + " [Run]")); + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_COMMAND_NUI), "btn_cmd_group" + sGroup + "_tooltip", JsonString(sText + " [Run]")); + NuiSetBind(oDM, NuiFindWindow(oDM, "dm" + AI_COMMAND_NUI), "btn_cmd_group" + sGroup + "_label", JsonString(sText)); + jGroup = JsonArrayInsert(JsonArray(), JsonInt(1)); + } + string sUUID = GetObjectUUID(oTarget); + int nIndex = 1; + string sListUUID = JsonGetString(JsonArrayGet(jGroup, nIndex)); + while(sListUUID != "") + { + if(sListUUID == sUUID) + { + ai_SendMessages("This creature is already in the group!", AI_COLOR_RED, oDM); + return; + } + sListUUID = JsonGetString(JsonArrayGet(jGroup, ++nIndex)); + } + jGroup = JsonArrayInsert(jGroup, JsonString(sUUID)); + ai_SendMessages(sName + " has been saved to group" + sGroup, AI_COLOR_YELLOW, oDM); + SetLocalJson(oDM, "DM_GROUP" + sGroup, jGroup); + EnterTargetingMode(oDM, OBJECT_TYPE_CREATURE, MOUSECURSOR_PICKUP, MOUSECURSOR_PICKUP_DOWN); +} +void ai_MonsterAction(object oDM, object oTarget, location lLocation, int bRun, int nIndex) +{ + object oCreature = OBJECT_SELF; + int nObjectType = GetObjectType(oTarget); + ai_ClearCreatureActions(TRUE); + if(oTarget == GetArea(oDM)) + { + ActionMoveToLocation(lLocation, bRun); + } + else if(nObjectType == OBJECT_TYPE_CREATURE) + { + if(GetIsDead(oTarget)) return; + else if(GetIsEnemy(oTarget, oCreature)) + { + // Lock them into attacking this target only. + SetLocalObject(oCreature, AI_PC_LOCKED_TARGET, oTarget); + // This resets a creatures failed Moral save in combat. + if(GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_coward") + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, GetLocalString(oCreature, AI_DEFAULT_SCRIPT)); + } + if(ai_GetIsInCombat(oCreature)) ai_DoMonsterCombatRound(oCreature); + else + { + ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:"); + ai_StartMonsterCombat(oCreature); + } + if(nIndex == 1) + { + ai_SendMessages(GetName(oCreature) + "'s group is attacking " + GetName(oTarget), AI_COLOR_RED, oDM); + } + } + else if(oTarget == oDM) + { + if(GetLocalInt(oCreature, "AI_FOLLOWING_DM")) + { + ClearAllActions(FALSE, oCreature); + DeleteLocalInt(oCreature, "AI_FOLLOWING_DM"); + if(nIndex == 1) + { + ai_SendMessages(GetName(oCreature) + "'s group has stopped following you.", AI_COLOR_RED, oDM); + } + } + else + { + ActionForceFollowObject(oDM, 4.0); + SetLocalInt(oCreature, "AI_FOLLOWING_DM", TRUE); + if(nIndex == 1) + { + ai_SendMessages(GetName(oCreature) + "'s group is following you.", AI_COLOR_RED, oDM); + } + } + } + else + { + ActionMoveToObject(oTarget, TRUE); + // Player will be stuck with this variable if they are not using the AI. + DeleteLocalInt(oTarget, "AI_I_AM_BEING_HEALED"); + ActionDoCommand(ai_ActionTryHealing(oCreature, oTarget)); + if(nIndex == 1) + { + ai_SendMessages(GetName(oCreature) + "'s group is moving to and attempting to heal " + GetName(oTarget), AI_COLOR_RED, oDM); + } + } + } + else if(nObjectType == OBJECT_TYPE_DOOR) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oDM)) SetTrapDetectedBy(oTarget, oCreature); + if(GetTrapDetectedBy(oTarget, oCreature)) + { + ai_ReactToTrap(oCreature, oTarget, TRUE); + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + else if(GetLocked(oTarget)) ai_AttemptToByPassLock(oCreature, oTarget); + } + else if(GetLocked(oTarget)) ai_AttemptToByPassLock(oCreature, oTarget); + else if(GetIsOpen(oTarget)) + { + ActionCloseDoor(oTarget, TRUE); + } + else ActionOpenDoor(oTarget, TRUE); + } + else if(nObjectType == OBJECT_TYPE_ITEM) + { + ActionPickUpItem(oTarget); + } + else if(nObjectType == OBJECT_TYPE_PLACEABLE) + { + ActionMoveToObject(oTarget, TRUE); + if(GetHasInventory(oTarget)) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oDM)) SetTrapDetectedBy(oTarget, oCreature); + if(GetTrapDetectedBy(oTarget, oCreature)) + { + ai_ReactToTrap(oCreature, oTarget, TRUE); + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + if(GetLocked(oTarget)) + { + if(!ai_AttemptToByPassLock(oCreature, oTarget)) + { + AssignCommand(oCreature, ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oTarget) + " is locked!")); + } + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE); + } + else if(GetLocked(oTarget)) + { + if(ai_AttemptToByPassLock(oCreature, oTarget)) + { + AssignCommand(oCreature, ai_HaveCreatureSpeak(oCreature, 0, "This " + GetName(oTarget) + " is locked!")); + } + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); + return; + } + ActionDoCommand(ai_SearchObject(oCreature, oTarget, oDM, TRUE)); + } + DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE); + } + else if(nObjectType == OBJECT_TYPE_TRIGGER) + { + if(GetIsTrapped(oTarget)) + { + if(GetTrapDetectedBy(oTarget, oDM)) SetTrapDetectedBy(oTarget, oCreature); + if(GetTrapDetectedBy(oTarget, oCreature)) ai_ReactToTrap(oCreature, oTarget, TRUE); + } + } + EnterTargetingMode(oDM, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK); +} +void ai_DMAction(object oDM, object oTarget, location lLocation, string sTargetMode) +{ + string sGroup = GetStringRight(sTargetMode, 1); + json jGroup = GetLocalJson(oDM, "DM_GROUP" + sGroup); + int bRun = JsonGetInt(JsonArrayGet(jGroup, 0)); + int nIndex = 1; + string sUUID = JsonGetString(JsonArrayGet(jGroup, nIndex)); + object oCreature; + while(sUUID != "") + { + oCreature = GetObjectByUUID(sUUID); + AssignCommand(oCreature, ai_MonsterAction(oDM, oTarget, lLocation, bRun, nIndex)); + sUUID = JsonGetString(JsonArrayGet(jGroup, ++nIndex)); + } + if(nIndex == 0) ai_SendMessages("Group" + sGroup + " is empty!", AI_COLOR_RED, oDM); +} +void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem) +{ + int nIndex; + if(GetStringLength(sElem) == 13) nIndex = StringToInt(GetStringRight(sElem, 2)); + else nIndex = StringToInt(GetStringRight(sElem, 1)); + SetLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX", nIndex); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jSpell = JsonArrayGet(jWidget, nIndex); + int nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + int nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + if(nClass == -1) // This is an Item. + { + object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5))); + int nBaseItemType = GetBaseItemType(oItem); + if(Get2DAString("spells", "Range", nSpell) == "P" || // Self + nBaseItemType == BASE_ITEM_ENCHANTED_POTION || + nBaseItemType == BASE_ITEM_POTIONS) + { + int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4)); + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(nIprpSubType == GetItemPropertySubType(ipProperty)) break; + ipProperty = GetNextItemProperty(oItem); + } + if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oAssociate)); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + return; + } + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_USE_ITEM"); + if(nSpell == SPELL_HEALINGKIT) + { + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_MAGIC, MOUSECURSOR_NOMAGIC); + return; + } + } + else // Feats, Spells, Special Abilities. + { + int nFeat = JsonGetInt(JsonArrayGet(jSpell, 5)); + if(nFeat) + { + if(!nSpell || Get2DAString("spells", "Range", nSpell) == "P" || // Self + nFeat == FEAT_SUMMON_FAMILIAR || nFeat == FEAT_ANIMAL_COMPANION || + nFeat == FEAT_TURN_UNDEAD) + { + if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + // Adjust the spell used for wild shape and other shape feats. + if(nFeat == FEAT_WILD_SHAPE) nSpell += 607; + if(nFeat == FEAT_ELEMENTAL_SHAPE) + { + if(nSpell == 397) nSpell == SUBFEAT_ELEMENTAL_SHAPE_FIRE; + else if(nSpell == 398) nSpell == SUBFEAT_ELEMENTAL_SHAPE_WATER; + else if(nSpell == 399) nSpell == SUBFEAT_ELEMENTAL_SHAPE_EARTH; + else if(nSpell == 400) nSpell == SUBFEAT_ELEMENTAL_SHAPE_AIR; + } + // Do special targeting for attack feats. + if(nFeat == FEAT_STUNNING_FIST || nFeat == FEAT_DIRTY_FIGHTING || + nFeat == FEAT_WHIRLWIND_ATTACK || nFeat == FEAT_QUIVERING_PALM || + nFeat == FEAT_KNOCKDOWN || nFeat == FEAT_IMPROVED_KNOCKDOWN || + nFeat == FEAT_SAP || nFeat == FEAT_KI_DAMAGE || + nFeat == FEAT_DISARM || nFeat == FEAT_IMPROVED_DISARM || + nFeat == FEAT_SMITE_EVIL || nFeat == FEAT_SMITE_GOOD) + { + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_USE_FEAT"); + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_ATTACK, MOUSECURSOR_NOATTACK); + } + // Check feat and adjust if it is an action mode feat. + if(ai_SetActionMode(oAssociate, nFeat)) return; + AssignCommand(oAssociate, ActionUseFeat(nFeat, oAssociate, nSpell)); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + return; + } + SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_USE_FEAT"); + } + else SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_CAST_SPELL"); + } + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate); + int nObjectType; + string sTarget = Get2DAString("spells", "TargetType", nSpell); + int nTarget = ai_HexStringToInt(sTarget); + //SendMessageToPC(GetFirstPC(), "nTarget: " + IntToString(nTarget)); + if((nTarget & 1) && !(nTarget & 2) &&!(nTarget & 4)) + { + if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + ai_CastWidgetSpell(oPC, oAssociate, oAssociate, GetLocation(oAssociate)); + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate)); + return; + } + if((nTarget & 1) || (nTarget & 2)) nObjectType += OBJECT_TYPE_CREATURE; + if(nTarget & 4) nObjectType += OBJECT_TYPE_TILE; + if(nTarget & 8) nObjectType += OBJECT_TYPE_ITEM; + if(nTarget & 16) nObjectType += OBJECT_TYPE_DOOR; + if(nTarget & 32) nObjectType += OBJECT_TYPE_PLACEABLE; + if(nTarget & 64) nObjectType += OBJECT_TYPE_TRIGGER; + string sShape = Get2DAString("spells", "TargetShape", nSpell); + int nShape, nSetData; + float fRange; + if(oPC == oAssociate) + { + nSetData = TRUE; + fRange = ai_GetSpellRange(nSpell); + if(fRange == 0.1) fRange = 0.0; + } + if(sShape == "sphere") + { + nShape = SPELL_TARGETING_SHAPE_SPHERE; + nSetData = TRUE; + } + else if(sShape == "rectangle") + { + nShape = SPELL_TARGETING_SHAPE_RECT; + nSetData = TRUE; + } + else if(sShape == "hsphere") + { + nShape = SPELL_TARGETING_SHAPE_HSPHERE; + nSetData = TRUE; + } + else if(sShape == "cone") nShape = SPELL_TARGETING_SHAPE_CONE; + else nShape = SPELL_TARGETING_SHAPE_NONE; + if(nSetData) + { + float fSizeX = StringToFloat(Get2DAString("spells", "TargetSizeX", nSpell)); + float fSizeY = StringToFloat(Get2DAString("spells", "TargetSizeY", nSpell)); + int nFlags = StringToInt(Get2DAString("spells", "TargetFlags", nSpell)); + SetEnterTargetingModeData(oPC, nShape, fSizeX, fSizeY, nFlags, fRange); + } + EnterTargetingMode(oPC, nObjectType, MOUSECURSOR_MAGIC, MOUSECURSOR_NOMAGIC); +} +void ai_UpdateAssociateWidget(object oPC, object oAssociate) +{ + int nUIToken = NuiFindWindow(oPC, ai_GetAssociateType(oPC, oAssociate) + AI_WIDGET_NUI); + if(nUIToken) + { + DelayCommand(0.0, NuiDestroy(oPC, nUIToken)); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate)); + /* Not sure why I did this? + if(oPC != oAssociate) + { + nUIToken = NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI); + if(nUIToken) + { + DelayCommand(0.0, NuiDestroy(oPC, nUIToken)); + DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC)); + } + } */ + } +} +int ai_SetActionMode(object oAssociate, int nFeat) +{ + int nMode; + if(nFeat == FEAT_POWER_ATTACK) nMode = ACTION_MODE_POWER_ATTACK; + else if(nFeat == FEAT_RAPID_SHOT) nMode = ACTION_MODE_RAPID_SHOT; + else if(nFeat == FEAT_FLURRY_OF_BLOWS) nMode = ACTION_MODE_FLURRY_OF_BLOWS; + else if(nFeat == FEAT_IMPROVED_POWER_ATTACK) nMode = ACTION_MODE_IMPROVED_POWER_ATTACK; + else if(nFeat == FEAT_EXPERTISE) nMode = ACTION_MODE_EXPERTISE; + else if(nFeat == FEAT_IMPROVED_EXPERTISE) nMode = ACTION_MODE_IMPROVED_EXPERTISE; + else if(nFeat == FEAT_DIRTY_FIGHTING) nMode = ACTION_MODE_DIRTY_FIGHTING; + if(nMode) + { + SetActionMode(oAssociate, nMode, !GetActionMode(oAssociate, nMode)); + return TRUE; + } + return FALSE; +} diff --git a/src/module/nss/0i_spells.nss b/src/module/nss/0i_spells.nss new file mode 100644 index 0000000..b7b75e2 --- /dev/null +++ b/src/module/nss/0i_spells.nss @@ -0,0 +1,2157 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + Script Name: 0i_spells + Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts for base spells. + +Category: + Enhancement E + Protection P +Indiscriminant I + Discriminant D + Range R + Touch T + Summon S + Healing H + Cure C + +Buff Duration: +1 - All +2 - Short +3 - Long + +Buff Target: + 0 - Caster only + 1-6 Str, Dex, Con, Int, Wis, Cha: Highest Ability Score + 7 - Lowest AC + 8 - Lowest AC without AC Bonus + 9 - Highest Atk + 10 - Most Wounded + 11 - Lowest Fortitude + 12 - Lowest Reflex + 13 - Lowest Will + 14 - Lowest total saves + 15 - Buffs an Item + +Buff Groups: +-1 - Elemental Resistances. +-2 - Summons +-3 - AC (Non armor) +-4 - AC (for Armor/Shield) +-5 - Chance to Miss (Invisibility) +-6 - Regeneration +-7 - Globes of Invulnerablitity +-8 - Damage Reduction +-9 - Mantles +-10 - Alignment vs Chaos +-11 - Alignment vs Evil +-12 - Alignment vs Good +-13 - Alignment vs Law +-14 - Atk Bonus (for Weapon) +-15 - Light effects +-16 - Haste effects +-17 - Polymorph effects +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_messages" +#include "0i_states_cond" +#include "0i_items" +#include "X0_I0_POSITION" +struct stSpell +{ + object oPC; + object oCaster; + object oTarget; + int nBuffType; + int nTarget; + int nPosition; + int nClass; + int nLevel; + int nMaxSlots; + int nSlot; +}; +// Returns TRUE if oCreature can cast nSpell from nLevel. +int ai_GetCanCastSpell(object oCreature, int nSpell, int nClass, int nLevel, int nMetaMagic = 0, int nDomain = 0); +// Returns TRUE if oCreature is immune to petrification. +int ai_IsImmuneToPetrification(object oCaster, object oCreature); +// Returns TRUE if oCreature has an effect from a mind affecting spell. +int ai_DoIHaveAMindAffectingSpellOnMe(object oCreature); +// Returns TRUE if nSpell is a cure spell. +int ai_IsCureSpell(int nSpell); +// Returns TRUE if nSpell is an inflict spell. +int ai_IsInflictSpell(int nSpell); +// Returns TRUE if nSpell is an area of effect spell. +int ai_IsAreaOfEffectSpell(int nSpell); +// Returns 1(TRUE) if oAssociate is a spellcaster. +// Rturns 2(TRUE) if oAssociate is a memorizing spellcaster. +int ai_GetIsSpellCaster(object oAssociate); +// Returns TRUE if oCreature is immune to nSpells effects. +int ai_CreatureImmuneToEffect(object oCaster, object oCreature, int nSpell); +// Returns the ranged of nSpell from the spells.2da(Column "Range"). +// S = 8.0f, M = 20.0f, L = 40.0f, T = 5.0f, else = 0.1f; +float ai_GetSpellRange(int nSpell); +// Returns TRUE if oTarget has a spell that we would want to dispel. +// Checks for harmful effects as well as buffing effects. +int ai_CreatureHasDispelableEffect(object oCaster, object oCreature); +// Remove nEffectType of Type specified on oCreature; +// nEffectType uses the constants EFFECT_TYPE_* +void ai_RemoveASpecificEffect(object oCreature, int nEffectType); +// Returns TRUE if oCreature has nEffectType. +// nEffectType uses the constants EFFECT_TYPE_* +int ai_GetHasEffectType(object oCreature, int nEffectType); +// Checks oCreature for special abilities have a long duration. +void ai_CheckCreatureSpecialAbilities(object oCreature); +// Checks oCreature for the silence effect and if the spell only has a somatic component. +int ai_IsSilenced(object oCreature, int nSpell); +// Returns TRUE if ArcaneSpellFailure is too high to chance casting the spell. +int ai_ArcaneSpellFailureTooHigh(object oCreature, int nClass, int nLevel, int nSlot); +// Returns TRUE if oCaster casts nSpell on oTarget. +// This will only cast the spell if oTarget DOES NOT already have the spell +// effect, and the caster has the spell ready. +int ai_TryToCastSpell(object oCaster, int nSpell, object oTarget); +// In "Buff_Target" column the value of 0 in the "ai_spells.2da" references the Caster. +// In "Buff_Target" column this is value 1-6(STR, DEX, CON, INT, WIS, CHA) in the "ai_spells.2da". +object ai_BuffHighestAbilityScoreTarget(object oCaster, int nSpell, int nAbilityScore, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 7 in the "ai_spells.2da". +object ai_BuffLowestACTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 8 in the "ai_spells.2da". +object ai_BuffLowestACWithOutACBonus(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 9 in the "ai_spells.2da". +object ai_BuffHighestAttackTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 10 in the "ai_spells.2da". +object ai_BuffMostWoundedTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 11 in the "ai_spells.2da". +object ai_BuffLowestFortitudeSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 12 in the "ai_spells.2da". +object ai_BuffLowestReflexSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 13 in the "ai_spells.2da". +object ai_BuffLowestWillSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 14 in the "ai_spells.2da". +object ai_BuffLowestSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// In "Buff_Target" column this is value 15 in the "ai_spells.2da". +object ai_BuffItemTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_"); +// Returns a target for nSpell cast by oCaster based on ai_spells.2da file. +object ai_GetBuffTarget(object oCaster, int nSpell); +// Casts a memorized spell from oCaster of nClass, nSpellLevel, nSpellSlot on oTarget. +void ai_CastMemorizedSpell(object oCaster, int nClass, int nSpellLevel, int nSpellSlot, object oTarget, int bInstant, object oPC = OBJECT_INVALID); +// Casts a known spell from oCaster of nClass, nSpell on oTarget. +void ai_CastKnownSpell(object oCaster, int nClass, int nSpell, object oTarget, int bInstant, object oPC = OBJECT_INVALID); +// Returns true if the spell is cast. +// Checks if they have the spell and will cast it if possible. +int ai_CheckAndCastSpell(object oCaster, int nSpell, int nSpellGroup, float fDelay, object oTarget, object oPC = OBJECT_INVALID); +// Setup monsters for oCaster to buff in ai_CastSpells. +void ai_SetupMonsterBuffTargets(object oCaster); +// Setup the targets for an NPC to buff one of the PC's members or the whole group. +void ai_SetupAllyTargets(object oCaster, object oPC); +// Setup the targets for an NPC to heal one of the PC's members. +void ai_SetupAllyHealingTargets(object oCaster, object oPC); +// Clears the casters buff targets. +void ai_ClearBuffTargets(object oCaster, string sVariable); +// Cycles through a casters spells casting all buffs via actions. +void ai_ActionCastMemorizedBuff(struct stSpell stSpell); +// Cycles through a casters spells casting all buffs via actions. +void ai_ActionCastKnownBuff(struct stSpell stSpell); +// Checks oCaster for buffing spells and casts them based on nTarget; +// These are cast as actions and will happen at the speed based on +// AI_HENCHMAN_BUFF_DELAY, but are still actions. +// nTarget is 0-9 where 0 is all targets, 1 is oPC, 2 is the caster +// 3 Familiar, 4 is Animal Companion, 5 is Summons, 6 is Dominated, and 7+ is henchman. +// Targets must be defined in variable AI_ALLY_TARGET_* where * is 1 to #. +// nBuffType is the duration 1 - all, 2 - short, 3 - long. +void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC); +// Returns TRUE if oCaster cast spontaneous cure spell on oTarget. +// This uses an action and must use AssignCommand or OBJECT_SELF is the caster! +int ai_CastSpontaneousCure(object oCreature, object oTarget, object oPC); +// Returns TRUE if oCaster casts a memorized cure spell on oTarget. +// This uses an action and must use AssignCommand or OBJECT_SELF is the caster! +int ai_CastMemorizedHealing(object oCreature, object oTarget, object oPC, int nClass); +// Returns TRUE if oCaster casts a known cure spell on oTarget. +// This uses an action and must use AssignCommand or OBJECT_SELF is the caster! +int ai_CastKnownHealing(object oCreature, object oTarget, object oPC, int nClass); +// Returns TRUE if oCreature has an effect that will break their concentration. +int ai_ConcentrationCondition(object oCreature); +// Check to see if a spell's concentration has been broken, works for summons as well. +void ai_SpellConcentrationCheck(object oCaster); +// Returns TRUE if oCreature can safely cast nSpell defensively or has a good +// chance of casting while in melee. +int ai_CastInMelee(object oCreature, int nSpell, int nInMelee); +// Returns a float range for the caster to search for a target of an offensive spell. +float ai_GetOffensiveSpellSearchRange(object oCreature, int nSpell); +// Returns TRUE if nSpell is a cure spell and will not over heal for nDamage. +int ai_ShouldWeCastThisCureSpell(int nSpell, int nDamage); +// Casts the spell on the current target for oAssociate. +void ai_CastWidgetSpell(object oPC, object oAssociate, object oTarget, location lLocation); +// Uses the feat on the current target for oAssociate. +void ai_UseWidgetFeat(object oPC, object oAssociate, object oTarget, location lLocation); +// Uses the item on the current target for oAssociate. +void ai_UseWidgetItem(object oPC, object oAssociate, object oTarget, location lLocation); +int ai_GetCanCastSpell(object oCreature, int nSpell, int nClass, int nLevel, int nMetaMagic = 0, int nDomain = 0) +{ + int nIndex, nSpellCount, nClassPosition, nSlot, nMaxSlots, nPosition = 1; + while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + nClassPosition = GetClassByPosition(nPosition, oCreature); + if(nClassPosition == CLASS_TYPE_INVALID) return FALSE; + if(nClass = nClassPosition) + { + if(Get2DAString("classes", "SpellCaster", nClass) == "1") + { + nSlot = 0; + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + nMaxSlots = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel); + while(nSlot < nMaxSlots) + { + if(GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot) == nSpell && + GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot)) return TRUE; + nSlot++; + } + } + else return GetSpellUsesLeft(oCreature, nClass, nSpell, nMetaMagic, nDomain); + } + } + nPosition++; + } + return FALSE; +} +int ai_IsImmuneToPetrification(object oCaster, object oCreature) +{ + int nAppearance = GetAppearanceType(oCreature); + switch(nAppearance) + { + case APPEARANCE_TYPE_BASILISK: + case APPEARANCE_TYPE_COCKATRICE: + case APPEARANCE_TYPE_MEDUSA: + case APPEARANCE_TYPE_ALLIP: + case APPEARANCE_TYPE_ELEMENTAL_AIR: + case APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER: + case APPEARANCE_TYPE_ELEMENTAL_EARTH: + case APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER: + case APPEARANCE_TYPE_ELEMENTAL_FIRE: + case APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER: + case APPEARANCE_TYPE_ELEMENTAL_WATER: + case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER: + case APPEARANCE_TYPE_GOLEM_STONE: + case APPEARANCE_TYPE_GOLEM_IRON: + case APPEARANCE_TYPE_GOLEM_CLAY: + case APPEARANCE_TYPE_GOLEM_BONE: + case APPEARANCE_TYPE_GORGON: + case APPEARANCE_TYPE_HEURODIS_LICH: + case APPEARANCE_TYPE_LANTERN_ARCHON: + case APPEARANCE_TYPE_SHADOW: + case APPEARANCE_TYPE_SHADOW_FIEND: + case APPEARANCE_TYPE_SHIELD_GUARDIAN: + case APPEARANCE_TYPE_SKELETAL_DEVOURER: + case APPEARANCE_TYPE_SKELETON_CHIEFTAIN: + case APPEARANCE_TYPE_SKELETON_COMMON: + case APPEARANCE_TYPE_SKELETON_MAGE: + case APPEARANCE_TYPE_SKELETON_PRIEST: + case APPEARANCE_TYPE_SKELETON_WARRIOR: + case APPEARANCE_TYPE_SKELETON_WARRIOR_1: + case APPEARANCE_TYPE_SPECTRE: + case APPEARANCE_TYPE_WILL_O_WISP: + case APPEARANCE_TYPE_WRAITH: + case APPEARANCE_TYPE_BAT_HORROR: + case 405: // Dracolich: + case 415: // Alhoon + case 418: // shadow dragon + case 420: // mithral golem + case 421: // admantium golem + case 430: // Demi Lich + case 469: // animated chest + case 474: // golems + case 475: // golems + return TRUE; + } + // Petrification immunity can also be granted as an item property. + if(ResistSpell(oCaster, oCreature) == 2 ) return TRUE; + // Prevent people from petrifying DM, resulting in GUI even when effect is not successful. + if(!GetPlotFlag(oCreature) && GetIsDM(oCreature)) return TRUE; + return FALSE; +} +int ai_DoIHaveAMindAffectingSpellOnMe(object oCreature) +{ + if(GetHasSpellEffect(SPELL_SLEEP, oCreature) || + GetHasSpellEffect(SPELL_DAZE, oCreature) || + GetHasSpellEffect(SPELL_HOLD_ANIMAL, oCreature) || + GetHasSpellEffect(SPELL_HOLD_MONSTER, oCreature) || + GetHasSpellEffect(SPELL_HOLD_PERSON, oCreature) || + GetHasSpellEffect(SPELL_CHARM_MONSTER, oCreature) || + GetHasSpellEffect(SPELL_CHARM_PERSON, oCreature) || + GetHasSpellEffect(SPELL_CHARM_PERSON_OR_ANIMAL, oCreature) || + GetHasSpellEffect(SPELL_MASS_CHARM, oCreature) || + GetHasSpellEffect(SPELL_DOMINATE_ANIMAL, oCreature) || + GetHasSpellEffect(SPELL_DOMINATE_MONSTER, oCreature) || + GetHasSpellEffect(SPELL_DOMINATE_PERSON, oCreature) || + GetHasSpellEffect(SPELL_CONFUSION, oCreature) || + GetHasSpellEffect(SPELL_MIND_FOG, oCreature) || + GetHasSpellEffect(SPELL_CLOUD_OF_BEWILDERMENT, oCreature) || + GetHasSpellEffect(SPELLABILITY_BOLT_DOMINATE,oCreature) || + GetHasSpellEffect(SPELLABILITY_BOLT_CHARM,oCreature) || + GetHasSpellEffect(SPELLABILITY_BOLT_CONFUSE,oCreature) || + GetHasSpellEffect(SPELLABILITY_BOLT_DAZE,oCreature)) return TRUE; + return FALSE; +} +int ai_IsCureSpell(int nSpell) +{ + switch(nSpell) + { + case SPELL_CURE_CRITICAL_WOUNDS: + case SPELL_CURE_LIGHT_WOUNDS: + case SPELL_CURE_MINOR_WOUNDS: + case SPELL_CURE_MODERATE_WOUNDS: + case SPELL_CURE_SERIOUS_WOUNDS: + case SPELL_HEAL: return TRUE; break; + } + return FALSE; +} +int ai_IsInflictSpell(int nSpell) +{ + switch(nSpell) + { + case SPELL_INFLICT_CRITICAL_WOUNDS: + case SPELL_INFLICT_LIGHT_WOUNDS: + case SPELL_INFLICT_MINOR_WOUNDS: + case SPELL_INFLICT_MODERATE_WOUNDS: + case SPELL_INFLICT_SERIOUS_WOUNDS: + case SPELL_HARM: return TRUE; break; + } + return FALSE; +} +int ai_IsAreaOfEffectSpell(int nSpell) +{ + switch(nSpell) + { + case SPELL_ACID_FOG : + case SPELL_MIND_FOG : + case SPELL_STORM_OF_VENGEANCE: + case SPELL_WEB : + case SPELL_GREASE : + case SPELL_CREEPING_DOOM : +// case SPELL_DARKNESS : + case SPELL_SILENCE : + case SPELL_BLADE_BARRIER : + case SPELL_CLOUDKILL : + case SPELL_STINKING_CLOUD : + case SPELL_WALL_OF_FIRE : + case SPELL_INCENDIARY_CLOUD : + case SPELL_ENTANGLE : + case SPELL_EVARDS_BLACK_TENTACLES: + case SPELL_CLOUD_OF_BEWILDERMENT : + case SPELL_STONEHOLD : + case SPELL_VINE_MINE : + case SPELL_SPIKE_GROWTH : + case SPELL_DIRGE : + case 530 : // vine mine + case 531 : // vine mine + case 532 : // vine mine + case 961 : // Prismatic Sphere + return TRUE; + } + return FALSE; +} +int ai_GetIsSpellCaster(object oAssociate) +{ + int nIndex, nSpellCaster, nClass; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass == CLASS_TYPE_INVALID) return nSpellCaster; + if(Get2DAString("classes", "SpellCaster", nClass) == "1") + { + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") return 2; + else nSpellCaster = 1; + } + } + return nSpellCaster; +} +int ai_GetIsSpellBookRestrictedCaster(object oAssociate) +{ + int nIndex, nSpellCaster, nClass; + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex++) + { + nClass = GetClassByPosition(nIndex, oAssociate); + if(nClass == CLASS_TYPE_INVALID) return FALSE; + if(Get2DAString("classes", "SpellbookRestricted", nClass) == "1") return TRUE; + } + return FALSE; +} +int ai_CreatureImmuneToEffect(object oCaster, object oCreature, int nSpell) +{ + string sIType = Get2DAString("ai_spells", "ImmunityType", nSpell); + if(sIType != "") + { + if(AI_DEBUG) ai_Debug("0i_spells", "290", "Checking spell immunity type(" + sIType + ")."); + if(sIType == "Death" && GetIsImmune(oCreature, IMMUNITY_TYPE_DEATH)) return TRUE; + else if(sIType == "Level_Drain" && GetIsImmune(oCreature, IMMUNITY_TYPE_NEGATIVE_LEVEL)) return TRUE; + else if(sIType == "Ability_Drain" && GetIsImmune(oCreature, IMMUNITY_TYPE_ABILITY_DECREASE)) return TRUE; + else if(sIType == "Poison" && GetIsImmune(oCreature, IMMUNITY_TYPE_POISON)) return TRUE; + else if(sIType == "Disease" && GetIsImmune(oCreature, IMMUNITY_TYPE_DISEASE)) return TRUE; + else if(sIType == "Curse" && GetIsImmune(oCreature, IMMUNITY_TYPE_CURSED)) return TRUE; + else if(sIType == "Mind_Affecting" && GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS)) return TRUE; + else if(sIType == "Petrification" && ai_IsImmuneToPetrification(oCaster, oCreature)) return TRUE; + else if(sIType == "Fear" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_FEAR) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Sleep" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_SLEEP) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Paralysis" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_PARALYSIS) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Domination" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_DOMINATE) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Confusion" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_CONFUSED) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Blindness" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_BLINDNESS) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Dazed" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_DAZED) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + else if(sIType == "Charm" && + (GetIsImmune(oCreature, IMMUNITY_TYPE_CHARM) || + GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE; + // Check for damage immunities. + // Negative damage does not work on undead! + else if(sIType == "Negative" && GetRacialType(oCreature) == RACIAL_TYPE_UNDEAD) + { + if(AI_DEBUG) ai_Debug("0i_spell", "325", "Undead are immune to Negative energy!"); + return TRUE; + } + // Elemental damage resistances should be checked. + if(sIType == "Acid" || sIType == "Cold" || sIType == "Fire" || + sIType == "Electricty" || sIType == "Sonic") + { + if(ai_GetHasEffectType(oCreature, EFFECT_TYPE_DAMAGE_RESISTANCE)) + { + if(AI_DEBUG) ai_Debug("0i_spell", "334", GetName(oCreature) + " has damage resistance to my " + sIType + " spell!"); + return TRUE; + } + // Check for resistances and immunities. Treat resistance as immune. + int nIPResist = GetLocalInt(oCreature, sIPResistVarname); + if(AI_DEBUG) ai_Debug("0i_spell", "372", "nIPResist:" + IntToString(nIPResist)); + int nIPImmune = GetLocalInt(oCreature, sIPImmuneVarname) | nIPResist; + if(AI_DEBUG) ai_Debug("0i_spell", "374", "nIPImmune:" + IntToString(nIPImmune)); + if(nIPImmune > 0) + { + if(AI_DEBUG) ai_Debug("0i_spell", "391", GetName(oCreature) + " is immune/resistant to my " + sIType + " spell through an item!"); + if(sIType == "Acid" && (nIPImmune & DAMAGE_TYPE_ACID)) return TRUE; + else if(sIType == "Cold" && (nIPImmune & DAMAGE_TYPE_COLD)) return TRUE; + else if(sIType == "Fire" && (nIPImmune & DAMAGE_TYPE_FIRE)) return TRUE; + else if(sIType == "Electricity" && (nIPImmune & DAMAGE_TYPE_ELECTRICAL)) return TRUE; + else if(sIType == "Sonic" && (nIPImmune & DAMAGE_TYPE_SONIC)) return TRUE; + } + } + } + int nLevel = StringToInt(Get2DAString("spells", "Innate", nSpell)); + // Globe spells should be checked... + if((GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, oCreature) || + GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, oCreature)) && + nLevel < 4 && d100() < 75) return TRUE; + if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, oCreature) && + nLevel < 5 && d100() < 75) return TRUE; + // Check creatures items for immunity. + int nIndex; + json jSpellImmunity = GetLocalJson(oCreature, AI_TALENT_IMMUNITY); + json jSpell = JsonArrayGet(jSpellImmunity, nIndex); + while(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + if(nSpell == JsonGetInt(jSpell)) + { + if(AI_DEBUG) ai_Debug("0i_spells", "407", GetName(oCreature) + " is immune to the spell via an Item!"); + return TRUE; + } + jSpell = JsonArrayGet(jSpellImmunity, ++nIndex); + } + if(AI_DEBUG) ai_Debug("0i_spell", "347", GetName(oCreature) + " is not immune to the spell."); + return FALSE; +} +float ai_GetSpellRange(int nSpell) +{ + string sRange = Get2DAString("spells", "Range", nSpell); + if(sRange == "S") return AI_SHORT_DISTANCE; + else if(sRange == "M") return AI_MEDIUM_DISTANCE; + else if(sRange == "L") return AI_LONG_DISTANCE; + else if(sRange == "T") return AI_RANGE_MELEE; + return 0.1; +} +int ai_CreatureHasDispelableEffect(object oCaster, object oCreature) +{ + int nSpellID, nLastSpellID, bSpell, nDispelChance; + // Cycle through the targets effects. + effect eEffect = GetFirstEffect(oCreature); + if(AI_DEBUG) ai_Debug("0i_spells", "485", "nSpell: " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", GetEffectSpellId(eEffect)))) + + " oCreature: " + GetName(oCreature)); + while(GetIsEffectValid(eEffect)) + { + nSpellID = GetEffectSpellId(eEffect); + // -1 is not a spell. + if(AI_DEBUG) ai_Debug("0i_spells", "491", "nSpell: (" + IntToString(nSpellID) + ") " + + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpellID)))); + if(nSpellID > -1 && nLastSpellID != nSpellID) + { + // We check if the spell is Hostile(-1) or Helpful(+1). + if(Get2DAString("ai_spells", "HostileSetting", nSpellID) == "1") nDispelChance--; + else nDispelChance++; + if(AI_DEBUG) ai_Debug("0i_spells", "497", "HostileSetting: " + Get2DAString("ai_spells", "HostileSetting", nSpellID) + + " nDispelChance: " + IntToString(nDispelChance)); + } + nLastSpellID = nSpellID; + eEffect = GetNextEffect(oCreature); + } + // if the target has more Helpful spells than harmful spells effecting them + // then use dispel! + if(AI_DEBUG) ai_Debug("0i_spells", "505", "nDispelChance: " + IntToString(nDispelChance)); + return (nDispelChance > 0); +} +void ai_RemoveASpecificEffect(object oCreature, int nEffectType) +{ + effect eEffect = GetFirstEffect(oCreature); + //Search for the effect. + while(GetIsEffectValid(eEffect)) + { + if(GetEffectType(eEffect) == nEffectType) + { + //Remove effect. + RemoveEffect(oCreature, eEffect); + eEffect = GetFirstEffect(oCreature); + } + else eEffect = GetNextEffect(oCreature); + } +} +int ai_GetHasEffectType(object oCreature, int nEffectType) +{ + effect eEffect = GetFirstEffect(oCreature); + while(GetIsEffectValid(eEffect)) + { + if(GetEffectType(eEffect, TRUE) == nEffectType) return TRUE; + eEffect = GetNextEffect(oCreature); + } + return FALSE; +} +void ai_CheckCreatureSpecialAbilities(object oCreature) +{ + int nMaxSpecialAbilities = GetSpellAbilityCount(oCreature); + if(nMaxSpecialAbilities) + { + int nIndex, bCanCast; + // Struct is id, ready, level. + int nSpell; + while(nIndex < nMaxSpecialAbilities) + { + nSpell = GetSpellAbilitySpell(oCreature, nIndex); + if(GetSpellAbilityReady(oCreature, nSpell)) + { + bCanCast = FALSE; + if(GetSpellAbilityCasterLevel(oCreature, nIndex) > 4) + { + // 1 Min/Lvl spell that is too low of level so it must be cast at 5th lvl or greater. + if(nSpell == SPELL_FLAME_WEAPON) bCanCast = TRUE; + else if(nSpell == SPELL_BLESS) bCanCast = TRUE; + else if(nSpell == SPELL_AID) bCanCast = TRUE; + else if(nSpell == SPELL_DEATH_WARD) bCanCast = TRUE; + } + if(nSpell == SPELL_ENERGY_BUFFER) bCanCast = TRUE; + else if(nSpell == SPELL_PROTECTION_FROM_ELEMENTS) bCanCast = TRUE; + else if(nSpell == SPELL_RESIST_ELEMENTS) bCanCast = TRUE; + else if(nSpell == SPELL_ENDURE_ELEMENTS) bCanCast = TRUE; + else if(nSpell == SPELL_MAGE_ARMOR) bCanCast = TRUE; + else if(nSpell == SPELL_MAGIC_VESTMENT) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_MAGIC_WEAPON) bCanCast = TRUE; + else if(nSpell == SPELL_MAGIC_WEAPON) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_IX) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_VIII) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_VII) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_VI) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_V) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_IV) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_III) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_II) bCanCast = TRUE; + else if(nSpell == SPELL_SUMMON_CREATURE_I) bCanCast = TRUE; + else if(nSpell == SPELL_BARKSKIN) bCanCast = TRUE; + else if(nSpell == SPELL_SHIELD) bCanCast = TRUE; + else if(nSpell == SPELL_ENTROPIC_SHIELD) bCanCast = TRUE; + else if(nSpell == SPELL_SHIELD_OF_FAITH) bCanCast = TRUE; + else if(nSpell == SPELL_REMOVE_FEAR) bCanCast = TRUE; + else if(nSpell == SPELL_IRONGUTS) bCanCast = TRUE; + else if(nSpell == SPELL_PREMONITION) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_STONESKIN) bCanCast = TRUE; + else if(nSpell == SPELL_GHOSTLY_VISAGE) bCanCast = TRUE; + else if(nSpell == SPELL_IMPROVED_INVISIBILITY) bCanCast = TRUE; + else if(nSpell == SPELL_INVISIBILITY_SPHERE) bCanCast = TRUE; + else if(nSpell == SPELL_INVISIBILITY) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_BULLS_STRENGTH) bCanCast = TRUE; + else if(nSpell == SPELL_BULLS_STRENGTH) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_CATS_GRACE) bCanCast = TRUE; + else if(nSpell == SPELL_CATS_GRACE) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_EAGLE_SPLENDOR) bCanCast = TRUE; + else if(nSpell == SPELL_EAGLE_SPLEDOR) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_ENDURANCE) bCanCast = TRUE; + else if(nSpell == SPELL_ENDURANCE) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_FOXS_CUNNING) bCanCast = TRUE; + else if(nSpell == SPELL_FOXS_CUNNING) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_OWLS_WISDOM) bCanCast = TRUE; + else if(nSpell == SPELL_OWLS_WISDOM) bCanCast = TRUE; + else if(nSpell == SPELL_KEEN_EDGE) bCanCast = TRUE; + else if(nSpell == SPELL_ANIMATE_DEAD) bCanCast = TRUE; + else if(nSpell == SPELL_INVISIBILITY_PURGE) bCanCast = TRUE; + else if(nSpell == SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE) bCanCast = TRUE; + else if(nSpell == SPELL_DARKFIRE) bCanCast = TRUE; + else if(nSpell == SPELL_NEGATIVE_ENERGY_PROTECTION) bCanCast = TRUE; + else if(nSpell == SPELL_MAGIC_CIRCLE_AGAINST_GOOD) bCanCast = TRUE; + else if(nSpell == SPELL_FREEDOM_OF_MOVEMENT) bCanCast = TRUE; + else if(nSpell == SPELL_NEUTRALIZE_POISON) bCanCast = TRUE; + else if(nSpell == SPELL_MIND_BLANK) bCanCast = TRUE; + else if(nSpell == SPELL_LESSER_MIND_BLANK) bCanCast = TRUE; + else if(nSpell == SPELL_SPELL_RESISTANCE) bCanCast = TRUE; + else if(nSpell == SPELL_PROTECTION_FROM_GOOD) bCanCast = TRUE; + else if(nSpell == SPELL_CREATE_UNDEAD) bCanCast = TRUE; + else if(nSpell == SPELL_PLANAR_ALLY) bCanCast = TRUE; + else if(nSpell == SPELL_LESSER_PLANAR_BINDING) bCanCast = TRUE; + else if(nSpell == SPELL_ETHEREALNESS) bCanCast = TRUE; + else if(nSpell == SPELL_PROTECTION_FROM_SPELLS) bCanCast = TRUE; + else if(nSpell == SPELL_SHADOW_SHIELD) bCanCast = TRUE; + else if(nSpell == SPELL_CREATE_GREATER_UNDEAD) bCanCast = TRUE; + else if(nSpell == SPELL_GREATER_PLANAR_BINDING) bCanCast = TRUE; + if(bCanCast && GetSpellAbilityReady(oCreature, nIndex)) + { + ActionCastSpellAtObject(nSpell, oCreature, 255, 0, 0, 0, TRUE); + } + } + nIndex++; + } + } +} +int ai_IsSilenced(object oCreature, int nSpell) +{ + if(Get2DAString("spells", "VS", nSpell) == "s") return FALSE; + if(ai_GetHasEffectType(oCreature, EFFECT_TYPE_SILENCE)) return TRUE; + return FALSE; +} +int ai_ArcaneSpellFailureTooHigh(object oCreature, int nClass, int nLevel, int nSlot) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "561", "Arcane Spells: " + Get2DAString("classes", "ASF", nClass) + + " Arcane Spell Failure: " + IntToString(GetArcaneSpellFailure(oCreature)) + + " AI_ASF_WILL_USE: " + IntToString(AI_ASF_WILL_USE)); + if(Get2DAString("classes", "ASF", nClass) == "1" && + GetArcaneSpellFailure(oCreature) > AI_ASF_WILL_USE) + { + if(GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot) == METAMAGIC_STILL) return FALSE; + return TRUE; + } + return FALSE; +} +int ai_TryToCastSpell(object oCaster, int nSpell, object oTarget) +{ + if(GetHasSpell(nSpell, oCaster) && !GetHasSpellEffect(nSpell, oTarget)) + { + ActionCastSpellAtObject(nSpell, oTarget); + return TRUE; + } + return FALSE; +} +int ai_SpellGroupNotCast(object oCreature, string sBuffGroup) +{ + return !GetLocalInt(oCreature, sBuffGroup); +} +void ai_ClearSpellsCastGroups(object oCreature) +{ + int nCounter; + for(nCounter = -1; nCounter <= AI_BUFF_GROUPS; nCounter--) + { + DeleteLocalInt(oCreature, "AI_USED_SPELL_GROUP_" + IntToString(nCounter)); + } +} +int ai_CanUseSpell(object oCaster, object oTarget, int nSpell, int nTargetType) +{ + // Should we ignore associates? + if(ai_GetAIMode(oCaster, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + // For ability scores we return a bonus to the ability to be checked against + // the target with the highest ability getting the spell first. + if(nTargetType == 1) // Ability score buff for strength. + { + // We don't want to buff the strength for someone using weapon finesse! + if(GetHasFeat(FEAT_WEAPON_FINESSE, oTarget)) return -5; + return TRUE; + } + if(nTargetType == 7) // Lowest AC. + { + // Stone bones only effects the undead. + if(nSpell == SPELL_STONE_BONES) + { + if(GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) return FALSE; + } + return TRUE; + } + if(nTargetType == 8) // Lowest AC without AC Bonus. + { + if(nSpell == SPELL_MAGIC_VESTMENT) + { + object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + if(oArmor == OBJECT_INVALID) return FALSE; + } + return TRUE; + } + if(nTargetType == 9) // Highest Attack. + { + return TRUE; + } + if(nTargetType == 10) // Most wounded, Lowest Hp. + { + return TRUE; + } + if(nTargetType == 11) // Lowest Fortitude save. + { + return TRUE; + } + if(nTargetType == 12) // Lowest Reflex save. + { + return TRUE; + } + if(nTargetType == 13) // Lowest Will save. + { + return TRUE; + } + if(nTargetType == 14) // Lowest Save. + { + return TRUE; + } + if(nSpell == SPELL_MAGIC_FANG) + { + object oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCaster); + if(oTarget != oCompanion) return FALSE; + } + return TRUE; +} +// Used to check if the targets weapon can be buffed by the spells effects. +int ai_CanItemBeBuffed(int nSpell, object oTarget) +{ + object oWeapon, oArmor; + if(nSpell == SPELL_MAGIC_WEAPON || nSpell == SPELL_GREATER_MAGIC_WEAPON || + nSpell == SPELL_BLADE_THIRST) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_ENHANCEMENT_BONUS)) return FALSE; + } + else if(nSpell == SPELL_MAGIC_VESTMENT) + { + oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + if(oArmor == OBJECT_INVALID) return FALSE; + if(ai_GetHasItemProperty(oArmor, ITEM_PROPERTY_AC_BONUS)) return FALSE; + } + else if(nSpell == SPELL_DARKFIRE) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_ON_HIT_PROPERTIES, 127)) return FALSE; + } + else if(nSpell == SPELL_FLAME_WEAPON) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_ON_HIT_PROPERTIES, 124)) return FALSE; + } + else if(nSpell == SPELL_KEEN_EDGE) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsSlashingWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_KEEN)) return FALSE; + } + else if(nSpell == SPELL_DEAFENING_CLANG) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_ON_HIT_PROPERTIES, 137)) return FALSE; + } + else if(nSpell == SPELL_BLESS_WEAPON) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP, IP_CONST_RACIALTYPE_UNDEAD)) return FALSE; + } + else if(nSpell == SPELL_HOLY_SWORD) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_HOLY_AVENGER)) return FALSE; + } + else if(nSpell == SPELL_BLACKSTAFF) + { + oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(GetBaseItemType(oWeapon) != BASE_ITEM_QUARTERSTAFF) return FALSE; + if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_ON_HIT_PROPERTIES, IP_CONST_ONHIT_DISPELMAGIC)) return FALSE; + } + return TRUE; +} +// In "Buff_Target" column the value of 0 in the "ai_spells.2da" references the Caster. +// In "Buff_Target" column this is value 1-6(STR, DEX, CON, INT, WIS, CHA) in the "ai_spells.2da". +object ai_BuffHighestAbilityScoreTarget(object oCaster, int nSpell, int nAbilityScore, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup)) return oMaster; + } + int nCntr = 1, nAB, nHighAB, nTarget, nUseSpell; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange) + { + nUseSpell = ai_CanUseSpell(oCaster, oTarget, nSpell, nAbilityScore + 1); + if(nUseSpell == 0) {} + else + { + nAB = GetAbilityScore(oTarget, nAbilityScore) + nUseSpell; + if(nAB > nHighAB) + {nHighAB = nAB; nTarget = nCntr; } + } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 7 in the "ai_spells.2da". +object ai_BuffLowestACTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + object oMaster = GetMaster(); + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 7)) return oMaster; + } + int nCntr = 1, nAC, nLowAC = 100, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nAC = GetAC(oTarget); + if(nAC < nLowAC && ai_CanUseSpell(oCaster, oTarget, nSpell, 7)) + {nLowAC = nAC; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); + return oTarget; +} +// In "Buff_Target" column this is value 8 in the "ai_spells.2da". +object ai_BuffLowestACWithOutACBonus(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 8)) return oMaster; + } + int nCntr = 1, nAC, nLowAC = 50, nTarget; + object oItem, oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nAC = GetAC(oTarget); + oItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + if(nAC < nLowAC && ai_CanUseSpell(oCaster, oTarget, nSpell, 8) && + !GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS)) + { + nLowAC = nAC; + nTarget = nCntr; + } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 9 in the "ai_spells.2da". +object ai_BuffHighestAttackTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 9)) return oMaster; + } + int nCntr = 1, nAtk, nHighAtk, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nAtk = GetBaseAttackBonus(oTarget); + if(nAtk > nHighAtk && ai_CanUseSpell(oCaster, oTarget, nSpell, 9)) + {nHighAtk = nAtk; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); + return oTarget; +} +// In "Buff_Target" column this is value 10 in the "ai_spells.2da". +object ai_BuffMostWoundedTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 9)) return oMaster; + } + int nCntr = 1, nDmg, nMostDmg, nHp, nLowHp = 10000, nTarget, nHpTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && + ai_SpellGroupNotCast(oTarget, sBuffGroup) && + ai_CanUseSpell(oCaster, oTarget, nSpell, 10)) + { + nHp = GetCurrentHitPoints(oTarget); + nDmg = GetMaxHitPoints(oTarget) - nHp; + if(nDmg > nMostDmg) { nMostDmg = nDmg; nTarget = nCntr; } + if(nHp < nLowHp) { nLowHp = nHp; nHpTarget = nCntr; } + } + // If no one is damage then put regeneration on the lowest hp target. + if(nMostDmg == 0) nTarget = nHpTarget; + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 11 in the "ai_spells.2da". +object ai_BuffLowestFortitudeSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 11)) return oMaster; + } + int nCntr = 1, nSave, nLowSave = 100, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nSave = GetFortitudeSavingThrow(oTarget); + if(nSave < nLowSave && ai_CanUseSpell(oCaster, oTarget, nSpell, 11)) + {nLowSave = nSave; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 12 in the "ai_spells.2da". +object ai_BuffLowestReflexSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 12)) return oMaster; + } + int nCntr = 1, nSave, nLowSave = 100, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nSave = GetReflexSavingThrow(oTarget); + if(nSave < nLowSave && ai_CanUseSpell(oCaster, oTarget, nSpell, 12)) + {nLowSave = nSave; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 13 in the "ai_spells.2da". +object ai_BuffLowestWillSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 13)) return oMaster; + } + int nCntr = 1, nSave, nLowSave = 100, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nSave = GetWillSavingThrow(oTarget); + if(nSave < nLowSave && ai_CanUseSpell(oCaster, oTarget, nSpell, 13)) + {nLowSave = nSave; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 14 in the "ai_spells.2da". +object ai_BuffLowestSaveTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(!GetHasSpellEffect(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup) && + ai_CanUseSpell(oCaster, oMaster, nSpell, 14)) return oMaster; + } + int nCntr = 1, nSave, nLowSave = 200, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && !GetHasSpellEffect(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nSave = GetFortitudeSavingThrow(oTarget) + GetReflexSavingThrow(oTarget) + GetWillSavingThrow(oTarget); + if(nSave < nLowSave && ai_CanUseSpell(oCaster, oTarget, nSpell, 14)) + {nLowSave = nSave; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + else return GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); +} +// In "Buff_Target" column this is value 15 in the "ai_spells.2da". +object ai_BuffItemTarget(object oCaster, int nSpell, string sBuffGroup, float fRange, string sTargetType = "AI_ALLY_TARGET_") +{ + if(ai_GetMagicMode(oCaster, AI_MAGIC_BUFF_MASTER)) + { + object oMaster = GetMaster(); + if(ai_CanItemBeBuffed(nSpell, oMaster) && + ai_SpellGroupNotCast(oMaster, sBuffGroup)) return oMaster; + } + int nCntr = 1, nAtk, nHighAtk = -9999, nTarget; + object oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nCntr)); + while (nCntr < 10) + { + if(oTarget != OBJECT_INVALID && ai_CanItemBeBuffed(nSpell, oTarget) && + GetDistanceBetween(oCaster, oTarget) <= fRange && ai_SpellGroupNotCast(oTarget, sBuffGroup)) + { + nAtk = GetBaseAttackBonus(oTarget); + if(nAtk > nHighAtk) + { nHighAtk = nAtk; nTarget = nCntr; } + } + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(++nCntr)); + } + if(nTarget == 0) return OBJECT_INVALID; + oTarget = GetLocalObject(oCaster, sTargetType + IntToString(nTarget)); + return oTarget; +} +object ai_GetBuffTarget(object oCaster, int nSpell) +{ + object oTarget = OBJECT_INVALID; + string sGroup = Get2DAString("ai_spells", "Buff_Group", nSpell); + if(sGroup == "") sGroup = IntToString(nSpell); + string sBuffGroup = "AI_USED_SPELL_GROUP_" + sGroup; + string sBuffTarget = Get2DAString("ai_spells", "Buff_Target", nSpell); + if(AI_DEBUG) ai_Debug("0i_spells", "769", "BuffTarget: " + sBuffTarget); + if(sBuffTarget == "0") + { + if(ai_SpellGroupNotCast(oCaster, sBuffGroup) && + !GetHasSpellEffect(nSpell, oCaster) && + ai_CanUseSpell(oCaster, oTarget, nSpell, 0)) + { + oTarget = oCaster; + } + } + else if(sBuffTarget == "1") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_STRENGTH, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "2") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_DEXTERITY, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "3") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_CONSTITUTION, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "4") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_INTELLIGENCE, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "5") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_WISDOM, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "6") + oTarget = ai_BuffHighestAbilityScoreTarget(oCaster, nSpell, ABILITY_CHARISMA, "", AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "7") + oTarget = ai_BuffLowestACTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "8") + oTarget = ai_BuffLowestACWithOutACBonus(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "9") + oTarget = ai_BuffHighestAttackTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "10") + oTarget = ai_BuffMostWoundedTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "11") + oTarget = ai_BuffLowestFortitudeSaveTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "12") + oTarget = ai_BuffLowestReflexSaveTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "13") + oTarget = ai_BuffLowestWillSaveTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "14") + oTarget = ai_BuffLowestSaveTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + else if(sBuffTarget == "15") + oTarget = ai_BuffItemTarget(oCaster, nSpell, sBuffGroup, AI_RANGE_BATTLEFIELD); + if(oTarget != OBJECT_INVALID) + { + SetLocalInt(oTarget, sBuffGroup, TRUE); + DelayCommand(6.0, DeleteLocalInt(oTarget, sBuffGroup)); + } + if(AI_DEBUG) ai_Debug("0i_spells", "939", GetName(oCaster) + " is targeting " + GetName(oTarget) + + " with " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))) + " spell" + + " sBuffGroup: " + sBuffGroup + "."); + return oTarget; +} +void ai_CastMemorizedSpell(object oCaster, int nClass, int nSpellLevel, int nSpellSlot, object oTarget, int bInstant, object oPC = OBJECT_INVALID) +{ + int nDomain; + int nSpell = GetMemorizedSpellId(oCaster, nClass, nSpellLevel, nSpellSlot); + if(GetMemorizedSpellIsDomainSpell(oCaster, nClass, nSpellLevel, nSpellSlot) == 1) nDomain = nSpellLevel; + else nDomain = 0; + int nMetaMagic = GetMemorizedSpellMetaMagic(oCaster, nClass, nSpellLevel, nSpellSlot); + if(AI_DEBUG) ai_Debug("0i_spells", "951", "nSpell: " + IntToString(nSpell) + " oTarget: " + GetName(oTarget) + + " nMetaMagic: " + IntToString(nMetaMagic) + " nDomain: " + IntToString(nDomain) + + " bInstant: " + IntToString(bInstant) + " nClass: " + IntToString(nClass)); + ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, FALSE, nDomain, 0, bInstant); + // Right now I cannot get nClass to work here... + //DelayCommand(fDelay, ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, FALSE, nDomain, 0, TRUE, nClass)); + if(oPC != OBJECT_INVALID) + { + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_SendMessages(GetName(oCaster) + " has cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_GREEN, oPC); + } +} +void ai_CastKnownSpell(object oCaster, int nClass, int nSpell, object oTarget, int bInstant, object oPC = OBJECT_INVALID) +{ + if(AI_DEBUG) ai_Debug("0i_Spells", "965", GetName(oCaster) + " is casting " + IntToString(nSpell)); + ActionCastSpellAtObject(nSpell, oTarget, 255, FALSE, 0, 0, bInstant); + // Right now I cannot get nClass to work here... + //ActionCastSpellAtObject(nSpell, oTarget, 255, FALSE, 0, 0, TRUE, nClass); + if(oPC != OBJECT_INVALID) + { + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_SendMessages(GetName(oCaster) + " has cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_GREEN, oPC); + } +} +int ai_CheckAndCastSpell(object oCaster, int nSpell, int nSpellGroup, float fDelay, object oTarget, object oPC = OBJECT_INVALID) +{ + int nClassCnt = 1, nClass, nMaxSlot, nSpellLevel, nSpellSlot, nMemorizedSpell, nDomain, nMetaMagic; + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + while(nClassCnt <= AI_MAX_CLASSES_PER_CHARACTER && nClass != CLASS_TYPE_INVALID) + { + nClass = GetClassByPosition(nClassCnt); + // Search all memorized spells for the spell. + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + // Check each level starting with the highest to lowest. + nSpellLevel = 0; + while(nSpellLevel < 10) + { + // Check each slot within each level. + nMaxSlot = GetMemorizedSpellCountByLevel(oCaster, nClass, nSpellLevel); + nSpellSlot = 0; + while(nSpellSlot < nMaxSlot) + { + if(GetMemorizedSpellReady(oCaster, nClass, nSpellLevel, nSpellSlot)) + { + nMemorizedSpell = GetMemorizedSpellId(oCaster, nClass, nSpellLevel, nSpellSlot); + if(nMemorizedSpell == nSpell) + { + ai_CastMemorizedSpell(oCaster, nClass, nSpellLevel, nSpellSlot, oTarget, FALSE, oPC); + return TRUE; + } + } + nSpellSlot++; + } + nSpellLevel++; + } + } + // Check non-memorized known lists for the spell. + else if(GetSpellUsesLeft(oCaster, nClass, nSpell)) + { + ai_CastKnownSpell(oCaster, nClass, nSpell, oTarget, FALSE, oPC); + return TRUE; + } + nClassCnt++; + } + return FALSE; +} +void ai_SetupMonsterBuffTargets(object oCaster) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1020", GetName(oCaster) + " is setting buff targets."); + SetLocalObject (oCaster, "AI_ALLY_TARGET_1" , oCaster); + SetLocalObject (oCaster, "AI_ALLY_TARGET_2", oCaster); + int nCntr = 1; + object oCreature = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oCaster, nCntr); + if(AI_DEBUG) ai_Debug("0i_spells", "864", GetName(oCreature) + " nCntr: " + IntToString(nCntr) + + " Distance: " + FloatToString(GetDistanceBetween(oCaster, oCreature), 0, 2)); + while(oCreature != OBJECT_INVALID && nCntr < 8 && GetDistanceBetween(oCaster, oCreature) < AI_RANGE_CLOSE) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1133", "Setting " + GetName(oCreature) + " as AI_ALLY_TARGET_" + IntToString(nCntr + 2)); + SetLocalObject (oCaster, "AI_ALLY_TARGET_" + IntToString(nCntr + 2), oCreature); + oCreature = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oCaster, ++nCntr); + if(AI_DEBUG) ai_Debug("0i_spells", "1136", GetName(oCreature) + " nCntr: " + IntToString(nCntr) + + " Distance: " + FloatToString(GetDistanceBetween(oCaster, oCreature), 0, 2)); + } +} +void ai_SetupAllyTargets(object oCaster, object oPC) +{ + // Setup our targets. + int nTarget; + if(oCaster != oPC) SetLocalObject (oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oPC); + SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCaster); + object oCreature = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oCreature); + int nCntr = 1; + int nMaxHenchman = GetMaxHenchmen() + nTarget; + object oHenchman = GetHenchman(oPC, nCntr); + while(oHenchman != OBJECT_INVALID && nCntr <= nMaxHenchman) + { + if(oHenchman == OBJECT_INVALID) break; + if(oHenchman != oCaster) SetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(++nTarget), oHenchman); + oHenchman = GetHenchman(oPC, ++nCntr); + } + nCntr = 1; + while(nCntr <= nMaxHenchman) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1166", "AI_ALLY_TARGET_" + IntToString(nCntr) + ": " + + GetName(GetLocalObject(oCaster, "AI_ALLY_TARGET_" + IntToString(nCntr)))); + nCntr++; + } +} +void ai_SetupAllyHealingTargets(object oCaster, object oPC) +{ + int nMaxHenchman = 1; + if(oPC == OBJECT_INVALID) oPC = oCaster; + if(ai_GetAIMode(oCaster, AI_MODE_PARTY_HEALING_OFF)) + { + if(!ai_GetAIMode(oCaster, AI_MODE_SELF_HEALING_OFF)) SetLocalObject(oCaster, "AI_ALLY_HEAL_1", oCaster); + } + else + { + int nTarget; + if(oCaster != oPC) + { + SetLocalObject (oCaster, "AI_ALLY_HEAL_1", oPC); + nTarget++; + } + if(!ai_GetAIMode(oCaster, AI_MODE_SELF_HEALING_OFF)) + { + SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCaster); + } + object oCreature = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + oCreature = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCaster); + if(oCreature != OBJECT_INVALID) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oCreature); + int nCntr = 1; + nMaxHenchman = GetMaxHenchmen() + nTarget; + object oHenchman = GetHenchman(oPC, nCntr); + while(oHenchman != OBJECT_INVALID && nTarget <= nMaxHenchman) + { + if(oHenchman == OBJECT_INVALID) break; + if(oHenchman != oCaster) SetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(++nTarget), oHenchman); + oHenchman = GetHenchman(oPC, ++nCntr); + } + } + int nCntr = 1; + while(nCntr <= nMaxHenchman) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1211", "AI_ALLY_HEAL_" + IntToString(nCntr) + ": " + + GetName(GetLocalObject(oCaster, "AI_ALLY_HEAL_" + IntToString(nCntr++)))); + } +} +void ai_ClearBuffTargets(object oCaster, string sVariable) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1216", GetName(oCaster) + " is clearing " + sVariable + " targets."); + int nIndex; + int nMaxTargets = GetMaxHenchmen() + 6; + for(nIndex = 1; nIndex < nMaxTargets; nIndex++) + { + DeleteLocalObject (oCaster, sVariable + IntToString(nIndex)); + } +} +void ai_CheckForPerDayProperties(object oCreature, object oItem, int nBuffType, int bEquiped = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1150", "Checking Item properties on " + GetName(oItem)); + // We have established that we can use the item if it is equiped. + if(!bEquiped && !ai_CheckIfCanUseItem(oCreature, oItem)) return; + int nPerDay, nCharges, nUses, nSpellBuffDuration; + int nIprpSubType, nSpell, nLevel, nIPType, nIndex; + object oTarget; + itemproperty ipProp = GetFirstItemProperty(oItem); + // Lets skip this if there are no properties. + if(!GetIsItemPropertyValid(ipProp)) return; + // Check for cast spell property and add them to the talent list. + while(GetIsItemPropertyValid(ipProp)) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1163", "ItempropertyType(15): " + IntToString(GetItemPropertyType(ipProp))); + nIPType = GetItemPropertyType(ipProp); + if(nIPType == ITEM_PROPERTY_CAST_SPELL) + { + // Get how they use the item (charges or uses per day). + nUses = GetItemPropertyCostTableValue(ipProp); + // We only check uses per day. + if(AI_DEBUG) ai_Debug("0i_spells", "1172", "Item uses: " + IntToString(nPerDay)); + if(nUses > 7 && nUses < 13) + { + nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(AI_DEBUG) ai_Debug("0i_spells", "1176", "Item uses per day: " + IntToString(nPerDay)); + if(nPerDay > 0) + { + // SubType is the ip spell index for iprp_spells.2da + nIprpSubType = GetItemPropertySubType(ipProp); + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell)); + if(AI_DEBUG) ai_Debug("0i_spells", "1183", "nSpell: " + IntToString(nSpell) + + " nBuffType: " + IntToString(nBuffType) + + " nSpellBuffDuration: " + IntToString(nSpellBuffDuration)); + if(nBuffType == nSpellBuffDuration || nBuffType == 1) + { + oTarget = ai_GetBuffTarget(oCreature, nSpell); + if(oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1190", GetName(oCreature) + " is using" + + GetName(oItem) + " to cast " + IntToString(nSpell) + + " on " + GetName(oTarget)); + ActionUseItemOnObject(oItem, ipProp, oTarget); + } + } + } + } + } + ipProp = GetNextItemProperty(oItem); + } +} +void ai_CheckForPerDayItems(object oCreature, object oPC, int nBuffType) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1198", GetName(oCreature) + ": Checking items for per day buffs."); + if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC_ITEMS)) + { + int bEquiped; + string sSlots; + // Cycle through all the creatures inventory items. + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetIdentified(oItem)) + { + // Does the item need to be equiped to use its powers? + sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)); + if(AI_DEBUG) ai_Debug("0i_talents", "1211", GetName(oItem) + " requires " + Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) + " slots."); + if(sSlots == "0x00000") ai_CheckForPerDayProperties(oCreature, oItem, nBuffType); + } + oItem = GetNextItemInInventory(oCreature); + } + int nSlot; + // Cycle through all the creatures equiped items. + oItem = GetItemInSlot(nSlot, oCreature); + while(nSlot < 11) + { + if(oItem != OBJECT_INVALID) ai_CheckForPerDayProperties(oCreature, oItem, nBuffType, TRUE); + oItem = GetItemInSlot(++nSlot, oCreature); + } + oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature); + if(oItem != OBJECT_SELF) ai_CheckForPerDayProperties(oCreature, oItem, nBuffType, TRUE); + } + // Clean up our variables. Must be done here since these are actions! + int nCntr; + object oTarget; + while(nCntr < 11) + { + oTarget = GetLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nCntr)); + if(oTarget != OBJECT_INVALID) + { + ai_ClearSpellsCastGroups(oTarget); + DeleteLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nCntr)); + } + nCntr++; + } +} +void ai_CheckForBuffSpells(struct stSpell stSpell) +{ + ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC); + stSpell.nPosition = 1; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + if(AI_DEBUG) ai_Debug("0i_spells", "1208", "nClass: " + IntToString(stSpell.nClass)); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + if(AI_DEBUG) ai_Debug("0i_spells", "1210", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + if(AI_DEBUG) ai_Debug("0i_spells", "1214", "Memorizes Spells: " + Get2DAString("classes", "MemorizesSpells", stSpell.nClass)); + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell)); + return; + } + else + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell)); + return; + } + } + stSpell.nPosition++; + } + ai_CheckForPerDayItems(stSpell.oCaster, stSpell.oPC, stSpell.nBuffType); +} +void ai_ActionCastMemorizedSummons(struct stSpell stSpell) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1122", "Start of ActionCastMemorizedSummons!"); + int nSpell; + string sBuffGroup, sBuffTarget; + object oTarget; + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + //ai_Debug("0i_spells", "1128", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + //ai_Debug("0i_spells", "1131", "nLevel: " + IntToString(stSpell.nLevel)); + while(stSpell.nLevel > -1) + { + //ai_Debug("0i_spells", "1134", "nMaxSlots: " + IntToString(stSpell.nMaxSlots) + + // " nSlots: " + IntToString(stSpell.nSlot)); + while(stSpell.nSlot < stSpell.nMaxSlots) + { + //ai_Debug("0i_spells", "1238", "Ready: " + IntToString(GetMemorizedSpellReady(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot))); + if(GetMemorizedSpellReady(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot)) + { + nSpell = GetMemorizedSpellId(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot); + //ai_Debug("0i_spells", "1142", "nSpell: " + IntToString(nSpell)); + if(Get2DAString("ai_spells", "Category", nSpell) == "S") + { + SetLocalInt(stSpell.oCaster, "AI_USED_SPELL_GROUP_-2", TRUE); + ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, stSpell.oCaster, TRUE, stSpell.oPC); + stSpell.nPosition = 1; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + DelayCommand(2.0, ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC)); + DelayCommand(2.0 + 0.5, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell))); + return; + } + } + stSpell.nSlot++; + } + stSpell.nLevel--; + //ai_Debug("0i_spells", "1153", "nLevel: " + IntToString(stSpell.nLevel)); + if(stSpell.nLevel > -1) + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + } + } + } + stSpell.nPosition++; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + //ai_Debug("0i_spells", "1164", "nClass: " + IntToString(stSpell.nClass)); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nSlot = 0; + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + } + else + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell)); + return; + } + } + } + ai_CheckForBuffSpells(stSpell); +} +void ai_ActionCastKnownSummons(struct stSpell stSpell) +{ + //ai_Debug("0i_spells", "1184", "Start of ActionCastKnownSummons!"); + int nSpell; + string sBuffGroup, sBuffTarget; + object oTarget; + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + //ai_Debug("0i_spells", "1190", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + //ai_Debug("0i_spells", "1193", "nLevel: " + IntToString(stSpell.nLevel)); + while(stSpell.nLevel > -1) + { + if(stSpell.nMaxSlots) + { + //ai_Debug("0i_spells", "1198", "nMaxSlots: " + IntToString(stSpell.nMaxSlots) + + // " nSlots: " + IntToString(stSpell.nSlot)); + while(stSpell.nSlot < stSpell.nMaxSlots) + { + nSpell = GetKnownSpellId(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot); + //ai_Debug("0i_spells", "1203", "Ready: " + IntToString(GetSpellUsesLeft(stSpell.oCaster, stSpell.nClass, nSpell))); + if(GetSpellUsesLeft(stSpell.oCaster, stSpell.nClass, nSpell)) + { + if(Get2DAString("ai_spells", "Category", nSpell) == "S") + { + SetLocalInt(stSpell.oCaster, "AI_USED_SPELL_GROUP_S", TRUE); + //ai_Debug("0i_spells", "1209", "nSpell: " + IntToString(nSpell)); + ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, stSpell.oCaster, TRUE, stSpell.oPC); + stSpell.nPosition = 1; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC); + DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell))); + return; + } + } + stSpell.nSlot++; + } + } + stSpell.nLevel--; + //ai_Debug("0i_spells", "1218", "nLevel: " + IntToString(stSpell.nLevel)); + if(stSpell.nLevel > -1) + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + } + } + } + stSpell.nPosition++; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + //ai_Debug("0i_spells", "1229", "nClass: " + IntToString(stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nSlot = 0; + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell)); + return; + } + else stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + } + } + ai_CheckForBuffSpells(stSpell); +} +void ai_ActionCastMemorizedBuff(struct stSpell stSpell) +{ + int nSpell; + string sBuffGroup, sBuffTarget; + object oTarget; + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + ai_Debug("0i_spells", "1252", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + ai_Debug("0i_spells", "1255", "nLevel: " + IntToString(stSpell.nLevel)); + while(stSpell.nLevel > -1) + { + ai_Debug("0i_spells", "1258", "nMaxSlots: " + IntToString(stSpell.nMaxSlots) + + " nSlots: " + IntToString(stSpell.nSlot)); + while(stSpell.nSlot < stSpell.nMaxSlots) + { + ai_Debug("0i_spells", "1262", "Ready: " + IntToString(GetMemorizedSpellReady(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot))); + if(GetMemorizedSpellReady(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot)) + { + nSpell = GetMemorizedSpellId(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot); + int nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell)); + ai_Debug("0i_spells", "1267", "nBuffType: " + IntToString(stSpell.nBuffType) + + " nSpellBuffDuration: " + IntToString(nSpellBuffDuration) + + " sBuffGroup: " + Get2DAString("ai_spells", "Buff_Group", nSpell)); + if(stSpell.nBuffType == nSpellBuffDuration || stSpell.nBuffType == 1) + { + if(stSpell.nTarget > 0) + { + sBuffTarget = Get2DAString("ai_spells", "Buff_Target", nSpell); + oTarget = GetLocalObject(stSpell.oCaster, "AI_ALLY_TARGET_" + IntToString(stSpell.nTarget)); + if(sBuffTarget != "0" || (sBuffTarget == "0" && stSpell.oCaster == oTarget)) + { + sBuffGroup = "AI_USED_SPELL_GROUP_" + Get2DAString("ai_spells", "Buff_Group", nSpell); + if(!ai_SpellGroupNotCast(oTarget, sBuffGroup)) oTarget == OBJECT_INVALID; + } + else oTarget == OBJECT_INVALID; + } + else oTarget = ai_GetBuffTarget(stSpell.oCaster, nSpell); + ai_Debug("0i_spells", "1284", "nSpell: " + IntToString(nSpell) + + " oTarget: " + GetName(oTarget)); + if(oTarget != OBJECT_INVALID) + { + ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, oTarget, TRUE, stSpell.oPC); + stSpell.nSlot++; + DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell))); + return; + } + } + } + stSpell.nSlot++; + } + stSpell.nLevel--; + ai_Debug("0i_spells", "1298", "nLevel: " + IntToString(stSpell.nLevel)); + if(stSpell.nLevel > -1) + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + } + } + } + stSpell.nPosition++; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + ai_Debug("0i_spells", "1309", "nClass: " + IntToString(stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nSlot = 0; + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + } + else + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell)); + return; + } + } + } + ai_CheckForPerDayItems(stSpell.oCaster, stSpell.oPC, stSpell.nBuffType); +} +void ai_ActionCastKnownBuff(struct stSpell stSpell) +{ + int nSpell; + string sBuffGroup, sBuffTarget; + object oTarget; + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + //ai_Debug("0i_spells", "1347", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + //ai_Debug("0i_spells", "1350", "nLevel: " + IntToString(stSpell.nLevel)); + while(stSpell.nLevel > -1) + { + if(stSpell.nMaxSlots) + { + //ai_Debug("0i_spells", "1356", "nMaxSlots: " + IntToString(stSpell.nMaxSlots) + + // " nSlots: " + IntToString(stSpell.nSlot)); + while(stSpell.nSlot < stSpell.nMaxSlots) + { + nSpell = GetKnownSpellId(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot); + int nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell)); + //ai_Debug("0i_spells", "1361", "nBuffType: " + IntToString(stSpell.nBuffType) + + // " nSpellBuffDuration: " + IntToString(nSpellBuffDuration) + + // " sBuffGroup: " + Get2DAString("ai_spells", "Buff_Group", nSpell)); + if(stSpell.nBuffType == nSpellBuffDuration || stSpell.nBuffType == 1) + { + //ai_Debug("0i_spells", "1367", "Ready: " + IntToString(GetSpellUsesLeft(stSpell.oCaster, stSpell.nClass, nSpell))); + if(GetSpellUsesLeft(stSpell.oCaster, stSpell.nClass, nSpell)) + { + if(stSpell.nTarget > 0) + { + sBuffTarget = Get2DAString("ai_spells", "Buff_Target", nSpell); + oTarget = GetLocalObject(stSpell.oCaster, "AI_ALLY_TARGET_" + IntToString(stSpell.nTarget)); + if(sBuffTarget != "0" || (sBuffTarget == "0" && stSpell.oCaster == oTarget)) + { + sBuffGroup = "AI_USED_SPELL_GROUP_" + Get2DAString("ai_spells", "Buff_Group", nSpell); + if(!ai_SpellGroupNotCast(oTarget, sBuffGroup)) oTarget == OBJECT_INVALID; + } + else oTarget == OBJECT_INVALID; + } + else oTarget = ai_GetBuffTarget(stSpell.oCaster, nSpell); + //ai_Debug("0i_spells", "1382", "nSpell: " + IntToString(nSpell) + + // " oTarget: " + GetName(oTarget)); + if(oTarget != OBJECT_INVALID) + { + ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, oTarget, TRUE, stSpell.oPC); + stSpell.nSlot++; + DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell))); + return; + } + } + } + stSpell.nSlot++; + } + } + stSpell.nLevel--; + //ai_Debug("0i_spells", "1396", "nLevel: " + IntToString(stSpell.nLevel)); + if(stSpell.nLevel > -1) + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + stSpell.nSlot = 0; + } + } + } + stSpell.nPosition++; + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + //ai_Debug("0i_spells", "921", "nClass: " + IntToString(stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + stSpell.nSlot = 0; + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell)); + return; + } + else stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + } + } + ai_CheckForPerDayItems(stSpell.oCaster, stSpell.oPC, stSpell.nBuffType); +} +void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC) +{ + // buff types: 1 - All, 2 - Short duration, 3 - Long duration + // Buff groups are used to prevent a henchmen to cast spells that have the same effect, + // for example: resist elements and protection from elements are similiar so the henchmen + // would cast only the most powerful among these if he has them both. + if(AI_DEBUG) ai_Debug("0i_spells", "1670", GetName(oCaster) + " is casting buffs: " + IntToString(nBuffType) + + " nTarget: " + IntToString(nTarget) + "!"); + struct stSpell stSpell; + stSpell.oPC = oPC; + stSpell.oCaster = oCaster; + stSpell.nBuffType = nBuffType; + stSpell.nTarget = nTarget; + stSpell.nPosition = 1; + // Look for summons spells on All, Long durations and the whole party. + if((nBuffType == 1 || nBuffType == 3) && nTarget == 0) + { + while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster); + if(AI_DEBUG) ai_Debug("0i_spells", "1684", "nClass: " + IntToString(stSpell.nClass)); + if(stSpell.nClass == CLASS_TYPE_INVALID) break; + if(AI_DEBUG) ai_Debug("0i_spells", "1686", "SpellCaster: " + Get2DAString("classes", "SpellCaster", stSpell.nClass)); + if(Get2DAString("classes", "SpellCaster", stSpell.nClass) == "1") + { + stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2; + if(AI_DEBUG) ai_Debug("0i_spells", "1692", "MemorizesSpells: " + Get2DAString("classes", "MemorizesSpells", stSpell.nClass)); + if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1") + { + stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedSummons(stSpell)); + return; + } + else + { + stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel); + AssignCommand(stSpell.oCaster, ai_ActionCastKnownSummons(stSpell)); + return; + } + } + stSpell.nPosition++; + } + // Exit here; if we summoned a monster then it linked off of that spell + // cast to continue the action queue for all buff spell cast actions. + } + ai_CheckForBuffSpells(stSpell); +} +int ai_CastSpontaneousCure(object oCreature, object oTarget, object oPC) +{ + if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) return FALSE; + if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_SPONTANEOUS_CURE)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_spells", "1643", GetName(oCreature) + " is looking to cast a spontaneous cure spell."); + if(!GetLevelByClass(CLASS_TYPE_CLERIC, oCreature)) return FALSE; + int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + int nSpell, nSlot, nMaxSlots, nLevel = 4; + int nSpellSave, nSlotSave, nLevelSave = 5; + string sSpellName; + while(nLevel > -1) + { + // We check CLASS_TYPE_CLERIC as thats the only class with spontaneous cure spells. + nMaxSlots = GetMemorizedSpellCountByLevel(oCreature, CLASS_TYPE_CLERIC, nLevel); + nSlot = 0; + if(AI_DEBUG) ai_Debug("0i_spells", "1653", "nLevel: " + IntToString(nLevel) + " nMaxSlots: " + IntToString(nMaxSlots)); + while(nSlot < nMaxSlots) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1656", "nSlot: " + IntToString(nSlot) + + " Spell Ready: " + IntToString(GetMemorizedSpellReady(oCreature, CLASS_TYPE_CLERIC, nLevel, nSlot))); + if(GetMemorizedSpellReady(oCreature, CLASS_TYPE_CLERIC, nLevel, nSlot)) + { + if(nLevel == 4) nSpell = SPELL_CURE_CRITICAL_WOUNDS; + else if(nLevel == 3) nSpell = SPELL_CURE_SERIOUS_WOUNDS; + else if(nLevel == 2) nSpell = SPELL_CURE_MODERATE_WOUNDS; + else if(nLevel == 1) nSpell = SPELL_CURE_LIGHT_WOUNDS; + else nSpell = 0; + if(AI_DEBUG) ai_Debug("0i_spells", "1665", "nSpell: " + IntToString(nSpell)); + if(nSpell) + { + if(ai_ShouldWeCastThisCureSpell(nSpell, nDamage)) + { + SetMemorizedSpellReady(oCreature, CLASS_TYPE_CLERIC, nLevel, nSlot, FALSE); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_SendMessages(GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_MAGENTA, oPC); + if(AI_DEBUG) ai_Debug("0i_spells", "1673", GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + "."); + ActionCastSpellAtObject(nSpell, oTarget, 255, TRUE); + return TRUE; + } + // Save the lowest level cure spell as we might need to cast it. + else if(nLevel < nLevelSave) + { + nSpellSave = nSpell; + nLevelSave = nLevel; + nSlotSave = nSlot; + } + } + } + nSlot++; + } + nLevel--; + } + // Did we find a cure spell? If we did then use it. + if(nSpellSave) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1693", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + "."); + SetMemorizedSpellReady(oCreature, CLASS_TYPE_CLERIC, nLevelSave, nSlotSave, FALSE); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpellSave))); + ai_SendMessages(GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_MAGENTA, oPC); + ActionCastSpellAtObject(nSpellSave, oTarget, 255, TRUE); + return TRUE; + } + return FALSE; +} +int ai_CastMemorizedHealing(object oCreature, object oTarget, object oPC, int nClass) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1702", GetName(oCreature) + " is looking to cast a memorized cure spell."); + int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + int nSpell, nSlot, nMaxSlots, nLevel = 9; + int nClassSave, nSlotSave, nLevelSave = 10; + while(nLevel > -1) + { + nMaxSlots = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel); + nSlot = 0; + if(AI_DEBUG) ai_Debug("0i_spells", "1710", "nLevel: " + IntToString(nLevel) + " nMaxSlots: " + IntToString(nMaxSlots)); + while(nSlot < nMaxSlots) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1713", "nSlot: " + IntToString(nSlot) + + " Spell Ready: " + IntToString(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot))); + if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot)) + { + nSpell = GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot); + if(ai_ShouldWeCastThisCureSpell(nSpell, nDamage)) + { + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(AI_DEBUG) ai_Debug("0i_spells", "1721", GetName(oCreature) + " has cast " + sSpellName + " on " + GetName(oTarget) + "."); + ai_CastMemorizedSpell(oCreature, nClass, nLevel, nSlot, oTarget, FALSE, oPC); + return TRUE; + } + // Save the lowest level cure spell as we might need to cast it. + else if(nLevel < nLevelSave && (nSpell > 26 && nSpell < 32)) + { + nClassSave = nClass; + nLevelSave = nLevel; + nSlotSave = nSlot; + } + } + nSlot++; + } + nLevel--; + } + // Did we find a cure spell? If we did then use it. + if(nLevelSave < 10) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1740", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + "."); + ai_CastMemorizedSpell(oCreature, nClassSave, nLevelSave, nSlotSave, oTarget, FALSE, oPC); + return TRUE; + } + return FALSE; +} +int ai_CastKnownHealing(object oCreature, object oTarget, object oPC, int nClass) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1748", GetName(oCreature) + " is looking to cast a known cure spell."); + int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + int nSpell, nSlot, nMaxSlots, nLevel = 9; + int nClassSave, nSpellSave, nLevelSave = 10; + while(nLevel > -1) + { + nMaxSlots = GetKnownSpellCount(oCreature, nClass, nLevel); + nSlot = 0; + if(AI_DEBUG) ai_Debug("0i_spells", "1756", "nLevel: " + IntToString(nLevel) + " nMaxSlots: " + IntToString(nMaxSlots)); + while(nSlot < nMaxSlots) + { + nSpell = GetKnownSpellId(oCreature, nClass, nLevel, nSlot); + if(AI_DEBUG) ai_Debug("0i_spells", "1760", "nSlot: " + IntToString(nSlot) + + " Spell Ready: " + IntToString(GetSpellUsesLeft(oCreature, nClass, nSpell))); + if(GetSpellUsesLeft(oCreature, nClass, nSpell)) + { + if(ai_ShouldWeCastThisCureSpell(nSpell, nDamage)) + { + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(AI_DEBUG) ai_Debug("0i_spells", "1767", GetName(oCreature) + " has cast " + sSpellName + " on " + GetName(oTarget) + "."); + ai_CastKnownSpell(oCreature, nClass, nSpell, oTarget, FALSE, oPC); + return TRUE; + } + // Save the lowest level cure spell as we might need to cast it. + else if(nLevel < nLevelSave && (nSpell > 26 && nSpell < 32)) + { + nClassSave = nClass; + nLevelSave = nLevel; + nSpellSave = nSpell; + } + } + nSlot++; + } + nLevel--; + } + return FALSE; + // Did we find a cure spell? If we did then use it. + if(nLevelSave < 10) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1781", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + "."); + ai_CastKnownSpell(oCreature, nClassSave, nSpellSave, oTarget, FALSE, oPC); + return TRUE; + } +} +int ai_ConcentrationCondition(object oCreature) +{ + int nType; + effect eEffect = GetFirstEffect(oCreature); + while(GetIsEffectValid(eEffect)) + { + nType = GetEffectType(eEffect); + if(nType == EFFECT_TYPE_STUNNED || nType == EFFECT_TYPE_PARALYZE || + nType == EFFECT_TYPE_SLEEP || nType == EFFECT_TYPE_FRIGHTENED || + nType == EFFECT_TYPE_PETRIFY || nType == EFFECT_TYPE_CONFUSED || + nType == EFFECT_TYPE_DOMINATED || nType == EFFECT_TYPE_POLYMORPH) + { + return TRUE; + } + eEffect = GetNextEffect(oCreature); + } + return FALSE; +} +void ai_SpellConcentrationCheck(object oCaster = OBJECT_SELF) +{ + object oMaster = GetMaster(); + if(GetLocalInt(oCaster,"X2_L_CREATURE_NEEDS_CONCENTRATION")) + { + if(GetIsObjectValid(oMaster)) + { + int nAction = GetCurrentAction(oMaster); + // master doing anything that requires attention and breaks concentration + if(nAction == ACTION_DISABLETRAP || nAction == ACTION_TAUNT || + nAction == ACTION_PICKPOCKET || nAction ==ACTION_ATTACKOBJECT || + nAction == ACTION_COUNTERSPELL || nAction == ACTION_FLAGTRAP || + nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL) + { + SignalEvent(oCaster,EventUserDefined(X2_EVENT_CONCENTRATION_BROKEN)); + } + else if(ai_ConcentrationCondition(oMaster)) + { + SignalEvent(oCaster,EventUserDefined(X2_EVENT_CONCENTRATION_BROKEN)); + } + } + } +} +int ai_CastInMelee(object oCreature, int nSpell, int nInMelee) +{ + // If this is a spell and we are in melee. + if(nInMelee > 0 && !GetHasFeat(FEAT_EPIC_IMPROVED_COMBAT_CASTING, oCreature)) + { + // Using DC 19 so we will use with up to a 50% failure. + int nSpellLevel = StringToInt(Get2DAString("spells", "Innate", nSpell)); + int nDC = AI_DEFENSIVE_CASTING_DC + nSpellLevel; + int nRoll = Random(AI_DEFENSIVE_CASTING_DIE) + 1; + int nConcentration = GetSkillRank(SKILL_CONCENTRATION, oCreature); + if(GetHasFeat(FEAT_COMBAT_CASTING, oCreature)) nConcentration += 4; + if(AI_DEBUG) ai_Debug("0i_spells", "1081", "Use Defensive Casting? nDC: " + IntToString(nDC) + " FEAT_COMBAT_CASTING: " + + IntToString(GetHasFeat(FEAT_COMBAT_CASTING, oCreature)) + + " nConcentration: " + IntToString(nConcentration) + " + nRoll: " + IntToString(nRoll)); + if(nConcentration + nRoll > nDC) + { + if(AI_DEBUG) ai_Debug("0i_spells", "1086", GetName(oCreature) + " is casting defensively!"); + SetActionMode(oCreature, ACTION_MODE_DEFENSIVE_CAST, TRUE); + } + // Defensive casting is a bad idea so maybe casting anyspell is a bad idea. + else + { + object oMelee = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(GetIsObjectValid(oMelee)) + { + nRoll = Random(AI_CASTING_IN_MELEE_ROLL) + 1; + nDC = AI_CASTING_IN_MELEE_DC + nSpellLevel + nInMelee * ai_GetCreatureAttackBonus(oMelee); + if(AI_DEBUG) ai_Debug("0i_spells", "1097", "Cast anyway: nConcentration: " + IntToString(nConcentration) + + " nRoll: " + IntToString(nRoll) + " nDC: " + IntToString(nDC) + + " oMelee: " + GetName(oMelee)); + if(nConcentration + nRoll > nDC) return TRUE; + if(AI_DEBUG) ai_Debug("0i_spells", "1101", GetName(oCreature) + " is not casting in melee against " + GetName(oMelee)); + return FALSE; + } + } + } + // We don't need to cast defensively so lets make sure it's off. + else if(GetActionMode(oCreature, ACTION_MODE_DEFENSIVE_CAST)) + { + SetActionMode(oCreature, ACTION_MODE_DEFENSIVE_CAST, FALSE); + } + return TRUE; +} +float ai_GetOffensiveSpellSearchRange(object oCreature, int nSpell) +{ + // Search the spell range + the distance to the closest enemy - 7.5 meters). + // This will keep the caster from running up on an enemy to cast. + // But allow them to move up some if needed. + float fRange = ai_GetSpellRange(nSpell); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + float fEnemyDistance = GetDistanceBetween(oCreature, oNearestEnemy); + // Spell range is less than the nearest enemy. Restrict based on nearest enemy. + // Spell range is less than the nearestenemy. Check enemy action then adjust. + if(fRange < fEnemyDistance) + { + // We check this because if the enemy is moving or has not started acting + // then we don't want to move up on them as they might move towards us! + int nAction = GetCurrentAction(oNearestEnemy); + if(AI_DEBUG) ai_Debug("0i_spells", "1130", GetName(oNearestEnemy) + " current action: " + IntToString(nAction)); + if(nAction != ACTION_MOVETOPOINT || nAction != ACTION_ITEMCASTSPELL || + nAction != ACTION_INVALID || nAction != ACTION_USEOBJECT || + nAction != ACTION_RANDOMWALK) fRange = fEnemyDistance + (fRange - 7.5); + } + if(fRange > AI_RANGE_BATTLEFIELD) return AI_RANGE_BATTLEFIELD; + else if(fRange < 0.1f) return 0.1f; + return fRange; +} +int ai_ShouldWeCastThisCureSpell(int nSpell, int nDamage) +{ + if(AI_DEBUG) ai_Debug("0i_spells", "1127", "nSpell: " + IntToString(nSpell) + " nDamage: " + + IntToString(nDamage)); + if(nSpell == SPELL_HEAL && nDamage > 50) return TRUE; + else if(nSpell == SPELL_CURE_CRITICAL_WOUNDS && nDamage > 31) return TRUE; + else if(nSpell == SPELL_CURE_SERIOUS_WOUNDS && nDamage > 23) return TRUE; + else if(nSpell == SPELL_CURE_MODERATE_WOUNDS && nDamage > 15) return TRUE; + else if(nSpell == SPELL_CURE_LIGHT_WOUNDS && nDamage > 6) return TRUE; + else if(nSpell == SPELL_CURE_MINOR_WOUNDS) return TRUE; + return FALSE; +} +void ai_CastWidgetSpell(object oPC, object oAssociate, object oTarget, location lLocation) +{ + int nIndex = GetLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + DeleteLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jSpell = JsonArrayGet(jWidget, nIndex); + int nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + int nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + int nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + int nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + //SendMessageToPC(oPC, "nSpell: " + IntToString(nSpell) + + // " oTarget: " + GetName(oTarget) + + // " nMetaMagic: " + IntToString(nMetaMagic) + + // " nDomain: " + IntToString(nDomain)); + if(GetCurrentAction(oAssociate) != ACTION_CASTSPELL) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + if(!GetIsObjectValid(oTarget)) + { + AssignCommand(oAssociate, ActionCastSpellAtLocation(nSpell, lLocation, nMetaMagic, FALSE, 0, FALSE, -1, FALSE, nDomain)); + } + else AssignCommand(oAssociate, ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, FALSE, nDomain)); + +} +void ai_UseWidgetFeat(object oPC, object oAssociate, object oTarget, location lLocation) +{ + int nIndex = GetLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + DeleteLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jFeat = JsonArrayGet(jWidget, nIndex); + int nFeat = JsonGetInt(JsonArrayGet(jFeat, 5)); + if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + //SendMessageToPC(oPC, "0i_spells, 2104, nFeat: " + IntToString(nFeat) + " oTarget: " + GetName(oTarget)); + if(!GetIsObjectValid(oTarget)) + { + AssignCommand(oAssociate, ActionUseFeat(nFeat, OBJECT_INVALID, 0, lLocation)); + } + else AssignCommand(oAssociate, ActionUseFeat(nFeat, oTarget)); +} +void ai_UseWidgetItem(object oPC, object oAssociate, object oTarget, location lLocation) +{ + int nIndex = GetLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + DeleteLocalInt(oAssociate, "AI_WIDGET_SPELL_INDEX"); + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata"); + json jSpells = JsonArrayGet(jAIData, 10); + json jWidget = JsonArrayGet(jSpells, 2); + json jItem = JsonArrayGet(jWidget, nIndex); + int nSpell = JsonGetInt(JsonArrayGet(jItem, 0)); + int nIprpSubType = JsonGetInt(JsonArrayGet(jItem, 4)); + object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jItem, 5))); + itemproperty ipProperty; + if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE)); + if(nSpell == SPELL_HEALINGKIT) + { + ipProperty = GetFirstItemProperty(oItem); + if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_HEALERS_KIT) + { + if(ai_GetIsCharacter(oPC)) ai_SendMessages(GetName(oAssociate) + " uses " + GetName(oItem) + " on " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC); + AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oTarget)); + return; + } + } + ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(nIprpSubType == GetItemPropertySubType(ipProperty)) break; + ipProperty = GetNextItemProperty(oItem); + } + if(!GetIsObjectValid(oTarget)) + { + AssignCommand(oAssociate, ActionUseItemAtLocation(oItem, ipProperty, lLocation)); + } + else AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oTarget)); +} diff --git a/src/module/nss/0i_states_cond.nss b/src/module/nss/0i_states_cond.nss new file mode 100644 index 0000000..4c77ccf --- /dev/null +++ b/src/module/nss/0i_states_cond.nss @@ -0,0 +1,423 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_states_cond +////////////////////////////////////////////////////////////////////////////////////////////////////// + Include scripts that handle states and conditions for combat. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +#include "0i_messages" +#include "0i_time" +//#include "X0_I0_COMBAT" +// Wrapper for ClearAllActions - we have added extra vars to be cleared as well. +// Note this references OBJECT_SELF! +void ai_ClearCreatureActions(int bClearCombatState = FALSE); +// Used in combat to keep track of the creatures last rounds action. +// One use is to make sure we don't use the same spell on the next round. +// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants. +void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE); +// Returns TRUE if oCreatures last rounds action is equal to nAction. +// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants. +int ai_CompareLastAction(object oCreature, int nAction); +// Sets the correct listen checks on oCreature. +void ai_SetListeningPatterns(object oCreature); +// Returns TRUE if oCreature is an elemental, undead, or golem i.e. non-living. +int ai_IsNonliving(int nRacialType); +// Returns TRUE if oCreature is in combat. +int ai_GetIsInCombat(object oCreature); +// Sets the time that this oCreature's current combat round started. +// Using action based combat rounds has an unfortunate side effect: +// Once you attack in melee you will continue to attack in melee do to hardcoded +// logic. This will "PUSH" your end of round back until it decides to stop attacking! +// We avoid this by setting the time and if we check for combat and 6 seconds has +// passed then we assume the current round is over, ClearAllActions, and start the next round. +void ai_SetCombatRound(object oCreature); +// Clears the current combat round timer by deleting the value. +void ai_EndCombatRound(object oCreature); +// Returns TRUE if AI_COMBAT_ROUND_IN_SECONDS has not passed since ai_SetCombatRound. +// If it returns FALSE then it will clear the current combat round timer. +int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS); +// Returns TRUE if oCreature is busy. +// This checks various actions to see if oCreature is busy; +// in combat, busy mode, Actions: attacking, casting spell, counterspelling, +// disabling trap, item casting spell, opening lock, resting, setting trap. +int ai_GetIsBusy(object oCreature); +// Returns a value based on the disabling effect. +// Dead = 1, Bleeding = 2, Dying = 2, Stunned = 29, Confused = 24, Paralyzed = 27 +// Frightened 25, Turned = 35, Petrified = 79, Charmed = 23, Disappearappear = 75, +// Time Stop = 66, Dazed = 28, Sleep = 30. +// Returns FALSE if not Disabled. +int ai_Disabled(object oCreature); +// Set one of the AI_MODE_* bitwise constants on oAssociate to bOn. +void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE); +// Return if nMode is set on oAssociate. Uses the AI_MODE_* bitwise constants. +int ai_GetAIMode(object oAssociate, int nBit); +// Set one of the AI_MAGIC_* bitwise constants on oAssociate to bOn. +void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE); +// Return if nMode is set on oAssociate. Uses the AI_MAGIC_* bitwise constants. +int ai_GetMagicMode(object oAssociate, int nBit); +// This is based off of the PC's settings for an associate and other creatures use a default. +// Set one of the AI_LOOT_* bitwise constants on oAssociate to bOn. +void ai_SetLootFilter(object oAssociate, int nBit, int bOn = TRUE); +// Return if nMode is set on oAssociate. Uses the AI_LOOT_* bitwise constants. +int ai_GetLootFilter(object oAssociate, int nBit); +// Set one of the AI_IP_* bitwise constants on oCreature to bOn. +void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE); +// Return if nMode is set on oCreature. Uses the AI_IP_* bitwise constants. +int ai_GetItemProperty(object oCreature, string sVarname, int nBit); +// Returns the number of hitpoints a creature must have to not be healed. +// This is based off of the PC's settings for an associate and other creatures use a default. +int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE); +// Returns TRUE if nCondition is within nCurrentConditions. +// nCurrentConditions is setup in ai_GetNegativeConditions. +int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions); +// Returns an integer with bitwise flags set that represent the current negative +// conditions on oCreature. ai_GetHasNegativeCondition uses this function. +int ai_GetNegativeConditions(object oCreature); +// Returns TRUE if oObject is in the line of sight of oCreature. +// If the creature is close LineOfSight doesn't work well. +int ai_GetIsInLineOfSight(object oCreature, object oObject); +// Add the specified condition flag to the behavior state of the caller +void ai_SetBehaviorState(int nCondition, int bValid = TRUE); +// Returns TRUE if the specified behavior flag is set on the caller +int ai_GetBehaviorState(int nCondition); +// Highlights the current mode for the widget passed. +void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken); +// Checks to see if the party scale is correctly adjusted. +void ai_CheckXPPartyScale(object oCreature); + +void ai_ClearCreatureActions(int bClearCombatState = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_states_cond", "89", GetName(OBJECT_SELF) + " is clearing actions (" + + IntToString(bClearCombatState) + ")!"); + DeleteLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE); + ClearAllActions(bClearCombatState); +} +void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE) +{ + SetLocalInt(oCreature, sLastActionVarname, nAction); +} +int ai_CompareLastAction(object oCreature, int nAction) +{ + // Are we checking to see if we cast a spell? + if(nAction == AI_LAST_ACTION_CAST_SPELL && + GetLocalInt(oCreature, sLastActionVarname) > -1) return TRUE; + // Check other last actions. + return (nAction == GetLocalInt(oCreature, sLastActionVarname)); +} +void ai_SetListeningPatterns(object oCreature) +{ + SetListenPattern(oCreature, AI_I_SEE_AN_ENEMY, AI_ALLY_SEES_AN_ENEMY); + SetListenPattern(oCreature, AI_I_HEARD_AN_ENEMY, AI_ALLY_HEARD_AN_ENEMY); + SetListenPattern(oCreature, AI_ATKED_BY_WEAPON, AI_ALLY_ATKED_BY_WEAPON); + SetListenPattern(oCreature, AI_ATKED_BY_SPELL, AI_ALLY_ATKED_BY_SPELL); + SetListenPattern(oCreature, AI_I_AM_WOUNDED, AI_ALLY_IS_WOUNDED); + SetListenPattern(oCreature, AI_I_AM_DEAD, AI_ALLY_IS_DEAD); + SetListenPattern(oCreature, AI_I_AM_DISEASED, AI_ALLY_IS_DISEASED); + SetListenPattern(oCreature, AI_I_AM_POISONED, AI_ALLY_IS_POISONED); + SetListenPattern(oCreature, AI_I_AM_WEAK, AI_ALLY_IS_WEAK); + SetListening(oCreature, TRUE); +} +int ai_IsNonliving(int nRacialType) +{ + switch(nRacialType) + { + case RACIAL_TYPE_CONSTRUCT: + case RACIAL_TYPE_ELEMENTAL: + case RACIAL_TYPE_UNDEAD: return TRUE; + } + return FALSE; +} +int ai_GetIsInCombat(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_states_cond", "110", GetName(oCreature) + " is in Combat: Enemy Numbers = " + IntToString(GetLocalInt(oCreature, AI_ENEMY_NUMBERS))); + + return GetLocalInt(oCreature, AI_ENEMY_NUMBERS); +} +void ai_SetCombatRound(object oCreature) +{ + SetLocalInt(oCreature, "AI_COMBAT_ROUND_START", SQLite_GetTimeStamp()); + if(AI_DEBUG) ai_Debug("0i_states_cond", "116", " ===============> " + GetName(oCreature) + " ROUND START:" + IntToString(SQLite_GetTimeStamp()) + " <==============="); +} +void ai_EndCombatRound(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_states_cond", "120", " ===============> " + GetName(oCreature) + " ROUND END:" + IntToString(SQLite_GetTimeStamp()) + " <==============="); + DeleteLocalInt(oCreature, "AI_COMBAT_ROUND_START"); +} +int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS) +{ + int nCombatRoundStart = GetLocalInt(oCreature, "AI_COMBAT_ROUND_START"); + if(AI_DEBUG) ai_Debug("0i_states_cond", "148", " nCombatRoundStart: " + IntToString(nCombatRoundStart)); + if(!nCombatRoundStart) return FALSE; + // New combat round calculator. If 6 seconds has passed then we are on a new round! + int nSQLTime = SQLite_GetTimeStamp(); + int nCombatRoundTime = nSQLTime - nCombatRoundStart; + if(AI_DEBUG) ai_Debug("0i_states_cond", "153", " SQLite_GetTimeStamp: " + IntToString(nSQLTime) + + "(" + IntToString(nSQLTime - nCombatRoundStart) + ")"); + if(nCombatRoundTime < nCombatRound) return TRUE; + ai_EndCombatRound(oCreature); + return FALSE; +} +// Testing to see if we can fix some delaying in combat. +int ai_GetIsBusy(object oCreature) +{ + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("0i_states_cond", "140", GetName(oCreature) + " Get is Busy, action: " + + IntToString(nAction)); + switch(nAction) + { + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_OPENLOCK : + case ACTION_REST : + case ACTION_DISABLETRAP : + case ACTION_ATTACKOBJECT : + case ACTION_COUNTERSPELL : + case ACTION_SETTRAP : return TRUE; + case ACTION_WAIT : + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("0i_states_cond", "153", "nCombatWait: " + IntToString(nCombatWait) + + " AI_AM_I_SEARCHING: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING))); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return TRUE; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + else if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) DeleteLocalInt(oCreature, AI_AM_I_SEARCHING); + return FALSE; + } + case ACTION_MOVETOPOINT : + { + return ai_GetIsInCombat(oCreature); + } + } + return FALSE; +} +int ai_Disabled(object oCreature) +{ + if(GetIsDead(oCreature)) return 1; + // Check for effects. + effect eEffect = GetFirstEffect(oCreature); + while(GetIsEffectValid(eEffect)) + { + switch(GetEffectType(eEffect)) + { + case EFFECT_TYPE_DOMINATED : + { + if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature); + return FALSE; + } + case EFFECT_TYPE_STUNNED : + case EFFECT_TYPE_DAZED : + case EFFECT_TYPE_SLEEP : + case EFFECT_TYPE_CONFUSED : + case EFFECT_TYPE_FRIGHTENED : + case EFFECT_TYPE_PARALYZE : + case EFFECT_TYPE_TURNED : + case EFFECT_TYPE_CHARMED : + case EFFECT_TYPE_PETRIFY : + case EFFECT_TYPE_TIMESTOP : + { + if(AI_DEBUG) ai_Debug("0i_stats_cond", "195", GetName(oCreature) + " is disabled(" + + IntToString(GetEffectType(eEffect)) + ")"); + return GetEffectType(eEffect); + } + } + eEffect = GetNextEffect(oCreature); + } + // Not Commandable is basically disabled as far as the AI is concerned. + if(!GetCommandable(oCreature)) + { + if(AI_DEBUG) ai_Debug("0i_stats_cond", "213", GetName(oCreature) + " is disabled(Not Commandable)!"); + return EFFECT_TYPE_PARALYZE; + } + if(AI_DEBUG) ai_Debug("0i_states_cond", "202", GetName(oCreature) + " is not disabled."); + return FALSE; +} +void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE) +{ + int nAIModes = GetLocalInt(oAssociate, sAIModeVarname); + if(bOn) nAIModes = nAIModes | nBit; + else nAIModes = nAIModes & ~nBit; + SetLocalInt(oAssociate, sAIModeVarname, nAIModes); + // Set widget to show the mode they are in. + +} +int ai_GetAIMode(object oAssociate, int nBit) +{ + if(GetLocalInt(oAssociate, sAIModeVarname) & nBit) return TRUE; + return FALSE; +} +void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE) +{ + int nMagicModes = GetLocalInt(oAssociate, sMagicModeVarname); + if(bOn) nMagicModes = nMagicModes | nBit; + else nMagicModes = nMagicModes & ~nBit; + SetLocalInt(oAssociate, sMagicModeVarname, nMagicModes); +} +int ai_GetMagicMode(object oAssociate, int nBit) +{ + if(GetLocalInt(oAssociate, sMagicModeVarname) & nBit) return TRUE; + return FALSE; +} +void ai_SetLootFilter(object oAssociate, int nLootBit, int bOn = TRUE) +{ + int nLootFilter = GetLocalInt(oAssociate, sLootFilterVarname); + if(bOn) nLootFilter = nLootFilter | nLootBit; + else nLootFilter = nLootFilter & ~nLootBit; + SetLocalInt(oAssociate, sLootFilterVarname, nLootFilter); +} +int ai_GetLootFilter(object oAssociate, int nBit) +{ + if(GetLocalInt(oAssociate, sLootFilterVarname) & nBit) return TRUE; + return FALSE; +} +void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE) +{ + int nItemProperties = GetLocalInt(oCreature, sVarname); + if(bOn) nItemProperties = nItemProperties | nBit; + else nItemProperties = nItemProperties & ~nBit; + SetLocalInt(oCreature, sVarname, nItemProperties); +} +int ai_GetItemProperty(object oCreature, string sVarname, int nBit) +{ + if(GetLocalInt(oCreature, sVarname) & nBit) return TRUE; + return FALSE; +} +int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE) +{ + if(bInCombat) return GetLocalInt(oCreature, AI_HEAL_IN_COMBAT_LIMIT); + else return GetLocalInt(oCreature, AI_HEAL_OUT_OF_COMBAT_LIMIT); +} +int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions) +{ + return (nCurrentConditions & nCondition); +} +int ai_GetNegativeConditions(object oCreature) +{ + int nCondition, nEffectType; + effect eEffect = GetFirstEffect(oCreature); + while(GetIsEffectValid (eEffect)) + { + // Rage and maybe other abilities might come from the oCreature! + if(GetEffectCreator(eEffect) != oCreature) + { + nEffectType = GetEffectType(eEffect); + switch(nEffectType) + { + case EFFECT_TYPE_DISEASE: nCondition = nCondition | AI_CONDITION_DISEASE; break; + case EFFECT_TYPE_POISON: nCondition = nCondition | AI_CONDITION_POISON; break; + case EFFECT_TYPE_CURSE: nCondition = nCondition | AI_CONDITION_CURSE; break; + case EFFECT_TYPE_BLINDNESS: + case EFFECT_TYPE_DEAF: nCondition = nCondition | AI_CONDITION_BLINDDEAF; break; + case EFFECT_TYPE_ABILITY_DECREASE: nCondition = nCondition | AI_CONDITION_ABILITY_DRAIN; break; + case EFFECT_TYPE_NEGATIVELEVEL: nCondition = nCondition | AI_CONDITION_LEVEL_DRAIN; break; + case EFFECT_TYPE_AC_DECREASE: nCondition = nCondition | AI_CONDITION_AC_DECREASE; break; + case EFFECT_TYPE_ATTACK_DECREASE: nCondition = nCondition | AI_CONDITION_ATK_DECREASE; break; + case EFFECT_TYPE_CHARMED: nCondition = nCondition | AI_CONDITION_CHARMED; break; + case EFFECT_TYPE_CONFUSED: nCondition = nCondition | AI_CONDITION_CONFUSED; break; + case EFFECT_TYPE_DAZED: nCondition = nCondition | AI_CONDITION_DAZED; break; + case EFFECT_TYPE_DAMAGE_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_DECREASE; break; + case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_I_DECREASE; break; + case EFFECT_TYPE_DOMINATED: nCondition = nCondition | AI_CONDITION_DOMINATED; break; + case EFFECT_TYPE_FRIGHTENED: nCondition = nCondition | AI_CONDITION_FRIGHTENED; break; + case EFFECT_TYPE_PARALYZE: nCondition = nCondition | AI_CONDITION_PARALYZE; break; + case EFFECT_TYPE_SAVING_THROW_DECREASE: nCondition = nCondition | AI_CONDITION_SAVE_DECREASE; break; + case EFFECT_TYPE_SKILL_DECREASE: nCondition = nCondition | AI_CONDITION_SKILL_DECREASE; break; + case EFFECT_TYPE_SLOW: nCondition = nCondition | AI_CONDITION_SLOW; break; + case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: nCondition = nCondition | AI_CONDITION_SR_DECREASE; break; + case EFFECT_TYPE_STUNNED: nCondition = nCondition | AI_CONDITION_STUNNED; break; + } + } + eEffect = GetNextEffect(oCreature); + } + return nCondition; +} +int ai_GetIsInLineOfSight(object oCreature, object oObject) +{ + // Creatures can block the line of sight so when close we shouldn't check. + if(GetDistanceBetween(oObject, oCreature) <= AI_RANGE_MELEE) return TRUE; + return LineOfSightObject(oCreature, oObject); +} +void ai_SetBehaviorState(int nCondition, int bValid = TRUE) +{ + int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER"); + if(bValid) + { + nPlot = nPlot | nCondition; + SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot); + } + else + { + nPlot = nPlot & ~nCondition; + SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot); + } +} +int ai_GetBehaviorState(int nCondition) +{ + int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER"); + if(nPlot & nCondition) return TRUE; + return FALSE; +} +void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken) +{ + if(oPC == oAssociate) return; + int bBool; + bBool = ai_GetAIMode(oAssociate,AI_MODE_DEFEND_MASTER); + NuiSetBind(oPC, nToken, "btn_cmd_guard_encouraged", JsonBool(bBool)); + bBool = ai_GetAIMode(oAssociate,AI_MODE_STAND_GROUND); + NuiSetBind(oPC, nToken, "btn_cmd_hold_encouraged", JsonBool(bBool)); + bBool = ai_GetAIMode(oAssociate,AI_MODE_FOLLOW); + NuiSetBind(oPC, nToken, "btn_cmd_follow_encouraged", JsonBool(bBool)); + if(!ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER) && + !ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND) && + !ai_GetAIMode(oAssociate, AI_MODE_FOLLOW)) bBool = TRUE; + else bBool = FALSE; + NuiSetBind(oPC, nToken, "btn_cmd_attack_encouraged", JsonBool(bBool)); +} +void ai_CheckXPPartyScale(object oCreature) +{ + object oModule = GetModule(); + if(!GetLocalInt(oModule, AI_RULE_PARTY_SCALE)) return; + object oMaster; + if(!ai_GetIsCharacter(oCreature)) + { + oMaster = GetMaster(oCreature); + while(oMaster != OBJECT_INVALID) + { + if(ai_GetIsCharacter(oMaster)) break; + oMaster = GetMaster(oMaster); + } + if(oMaster == OBJECT_INVALID) return; + } + else oMaster = oCreature; + float fDefaultXPScale = IntToFloat(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP)); + float fPartySize = 4.0; + int nAssociateType, nHenchman, nHenchAssociate; + object oHenchman; + for(nAssociateType = 1; nAssociateType <= 5; nAssociateType++) + { + if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) + { + for(nHenchman = 1; nHenchman <= AI_MAX_HENCHMAN; nHenchman++) + { + oHenchman = GetAssociate(nAssociateType, oMaster, nHenchman); + if(oHenchman != OBJECT_INVALID) + { + fPartySize += 1.0; + for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++) + { + if(GetAssociate(nHenchAssociate, oHenchman, 1) != OBJECT_INVALID) fPartySize += 1.0; + } + } + } + } + else if(GetAssociate(nAssociateType, oMaster, 1) != OBJECT_INVALID) fPartySize += 1.0; + } + int nXPScale = FloatToInt(fPartySize / 4.0 * fDefaultXPScale); + //SendMessageToPC(oMaster, GetName(oMaster) + " nXPScale = (3 + fPartySize / 4.0 * fDefaultXPScale)" + + // IntToString(nXPScale) + " = (" + FloatToString(fPartySize, 0, 1) + " / 4.0 * " + + // FloatToString(fDefaultXPScale, 0, 1) + ")"); + SetModuleXPScale(nXPScale); +} + diff --git a/src/module/nss/0i_talents.nss b/src/module/nss/0i_talents.nss new file mode 100644 index 0000000..fa773b9 --- /dev/null +++ b/src/module/nss/0i_talents.nss @@ -0,0 +1,3098 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0i_talents + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Fuctions to use a category of skills, feats, spells, or items. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_combat" +// ***************************************************************************** +// ************************* Try * Defensive Talents *************************** +// ***************************************************************************** +// These functions try to find and use a specific set of talents intelligently. + +// Returns TRUE if oCreature uses a healing talent on oTarge. +// nInMelee is the number of enemies the caller is in melee with. +// If oTarget is set then they will heal that target if they need it. +// Otherwise checks all allies to see who we should heal based on the talent. +int ai_TryHealingTalent(object oCreature, int nInMelee, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses a cure condition talent on an ally or self. +int ai_TryCureConditionTalent(object oCreature, int nInMelee, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses a defensive talent. +// Checks for a Defensive talent(Protection, Enhancement, or Summons). +// Randomizes the order to mix up spells in combat. +// if oTarget is set then the defensive talent will be cast on them or OBJECT_SELF. +int ai_TryDefensiveTalents(object oCreature, int nInMelee, int nMaxLevel, int nRound = 0, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses a defensive talent. +// Checks the enemy faction for most powerful class and picks a buff based on it. +//int ai_TryAdvancedBuffOnSelf(object oCreature, int nInMelee); +// Set any auras this oCreature has instantly. +// This can be done in the OnSpawn script, heart beat, or Perception. +void ai_SetAura(object oCreature); + +// ***************************************************************************** +// ************************ Try Physical Attack Talents ************************ +// ***************************************************************************** +// These functions try to find and use melee attack talents intelligently. + +// Wrapper for ActionAttack, oCreature uses nAction (attack) on oTarget. +// nInMelee is only used in AI_LAST_ACTION_RANGED_ATK actions. +// bPassive TRUE oCreature will not move while attacking. +// nActionMode, pass the action mode if one is being used. +void ai_ActionAttack(object oCreature, int nAction, object oTarget, int nInMelee = 0, int bPassive = FALSE, int nActionMode = 0); +// Returns TRUE if oCreature uses a dragons breath talent +// Check for dragon's attacks under TALENT_CATEGORY_DRAGONS_BREATH(19). +// nRound must be supplied so we can keep track of the breath uses. +int ai_TryDragonBreathAttack(object oCreature, int nRound, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses a dragons wing attacks. +// Checks to see if a dragon can use its wings on a nearby enemy. +// Checks the right side and then the left side to see if it can attack. +int ai_TryWingAttacks(object oCreature); +// Returns TRUE if oCreature uses a dragons tail slap. +// Looks behind the dragon to see if it can use it's tail slap on an enemy. +int ai_TryTailSlap(object oCreature); +// Returns TRUE if oCreature uses a dragons crush attack. +// Dragon can fly up and crash down on opponents to do bludgeoning damage. +// If 3 times smaller than the dragon they will take extra damage and be +// Knocked Down for 1 round if Reflex save is not made. +int ai_TryCrushAttack(object oCreature, object oTarget); +// Returns TRUE if oCreature uses a dragons tail sweep attack. +// If the enemy is 4 sizes smaller than it the dragon to use its tail to sweep +// behind it doing damage and knocking the opponents down. +int ai_TryTailSweepAttack(object oCreature); +// Returns TRUE if oCreature finds a good target and uses Sneak Attack. +int ai_TrySneakAttack(object oCreature, int nInMelee, int bAlwaysAtk = TRUE); +// Returns TRUE if oCreature finds a good ranged target and uses Sneak Attack. +int ai_TryRangedSneakAttack(object oCreature, int nInMelee); +// Returns TRUE if oCreature uses a harmful melee talent. +int ai_TryMeleeTalents(object oCreature, object oTarget); +// ***************************************************************************** +// ******************************* Try * Skills ******************************** +// ***************************************************************************** +// These functions try to find and use a specific set of skills intelligently. + +// Wrapper to have oCreature use nSkill on oTarget. +void ai_UseSkill(object oCreature, int nSkill, object oTarget); +// Returns TRUE if oCreature uses the parry skill on someone attacking them. +// Checks if doing a parry might be successful. +int ai_TryParry(object oCreature); +// Returns TRUE if oCreature uses the Taunt skill on oTarget. +// Checks if doing a taunt might be successful against oTarget. +int ai_TryTaunt(object oCreature, object oTarget); +// Returns TRUE if oCreature uses the Animial emapthy skill on oTarget. +// For it to work oTarget must be an Animal, Beast, or Magical Beast. +// Checks if doing Animal Empathy might be successful against oTarget. +int ai_TryAnimalEmpathy(object oCreature, object oTarget = OBJECT_INVALID); +// ***************************************************************************** +// ******************************** Try * Feats ******************************** +// ***************************************************************************** +// These functions try to find and use a specific set of feats intelligently. + +// Wrapper to have oCreature use nFeat on oTarget. +void ai_UseFeat(object oCreature, int nFeat, object oTarget, int nSubFeat = 0); +// Wrapper to have oCreature use nActionMode on oTarget. +// nInMelee is only used in AI_LAST_ACTION_RANGED_ATK actions. +// bPassive TRUE oCreature will not move while attacking. +void ai_UseFeatAttackMode(object oCreature, int nActionMode, int nAction, object oTarget, int nInMelee = 0, int bPassive = FALSE); +// Returns TRUE if oCreature uses Rage. +// This checks if they are already in a rage and if they have the Rage feat. +int ai_TryBarbarianRageFeat(object oCreature); +// Returns TRUE if oCreature uses Bard song. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TryBardSongFeat(object oCreature); +// Returns TRUE if oCreature uses Called shot. +// This checks if they have the feat and if its viable. +int ai_TryCalledShotFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Disarm. +// This checks if they have the feat and if its viable. +int ai_TryDisarmFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Divine Might. +// This only checks if they can use the feat and have turn undead uses left. +int ai_TryDivineMightFeat(object oCreature, int nInMelee); +// Returns TRUE if oCreature uses Divine Shield. +// This only checks if they can use the feat and have turn undead uses left. +int ai_TryDivineShieldFeat(object oCreature, int nInMelee); +// Returns TRUE if oCreature uses Expertise. +// This checks if they have the feat and if its viable. +// Also checks to see if the Improved Expertise feat would be better. +int ai_TryExpertiseFeat(object oCreature); +// Returns TRUE if oCreature uses Flurry of Blows. +// This checks if they have the feat and if its viable. +int ai_TryFlurryOfBlowsFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Improved Expertise. +// This checks if they have the feat and if its viable. +// Also checks to see if the Expertise feat would be better. +int ai_TryImprovedExpertiseFeat(object oCreature); +// Returns TRUE if oCreature uses Improved Power Attack. +// This checks if they have the feat and if its viable. +// Also checks to see if the Power Attack feat would be better. +int ai_TryImprovedPowerAttackFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Ki Damage. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TryKiDamageFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Knockdown. +// This checks if they have the feat and if its viable. +int ai_TryKnockdownFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses a polymorph self feat. +// This checks if they have the feat and will use the best one. +int ai_TryPolymorphSelfFeat(object oCreature); +// Returns TRUE if oCreature uses Power Attack. +// This checks if they have the feat and if its viable. +// Also checks to see if the Improved Power Attack would be better. +int ai_TryPowerAttackFeat(object oCreature, object oEnemy); +// Returns TRUE if oCreature uses Quivering palm. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TryQuiveringPalmFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Power Attack. +// This checks if they have the feat and if its viable. +// Using a bow and having arrows should be checked before calling this. +int ai_TryRapidShotFeat(object oCreature, object oTarget, int nInMelee); +// Returns TRUE if oCreature uses Sap. +// This checks if they have the feat and if its viable. +int ai_TrySapFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Smite evil. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TrySmiteEvilFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Smite good. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TrySmiteGoodFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses Stunning fists. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TryStunningFistFeat(object oCreature, object oTarget); +// Returns TRUE if oCreature uses a summon animal companion talent. +int ai_TrySummonAnimalCompanionTalent(object oCreature); +// Returns TRUE if oCreature uses a summon familiar talent. +int ai_TrySummonFamiliarTalent(object oCreature); +// Returns TRUE if oCreature uses the Lay on Hands feat talent. +int ai_TryLayOnHands(object oCreature); +// Returns TRUE if oCreature uses a turning talent. +int ai_TryTurningTalent(object oCreature); +// Returns TRUE if oCreature uses Whirlwind. +// This checks if they have the feat and if its viable. +int ai_TryWhirlwindFeat(object oCreature); +// Returns TRUE if oCreature uses Wholeness of Body. +// This checks if they have any uses left, have the feat and if its viable. +int ai_TryWholenessOfBodyFeat(object oCreature); +// ***************************************************************************** +// ***************************** TALENT SCRIPTS ****************************** +// ***************************************************************************** +// These functions do not fall into another section. + +// Returns the MaxLevel used in GetCreatureTalent for oCreature. +// This checks the intelligence and the level of oCreature. +// Returns either -1 (random) or 10 for all talents. +int ai_GetMonsterTalentMaxLevel(object oCreature); +// Returns the nMaxLevel used in GetCreatureTalent for oCreature. +// This checks the difficulty of the combat and the level of oCreature. +// Return a number equal to 1 and half the level of oCreature upto 10. +// The max spell level used is equal to nMaxLevel or less. +int ai_GetAssociateTalentMaxLevel(object oCreature, int nDifficulty); +// Returns TRUE if oCreature has nTalent. +// nTalent will be a spell in the spells.2da. +int ai_GetHasTalent(object oCreature, int nTalent); +// Saves a talent in JsonArray. +// Array: 0-Type (1-spell, 2-sp ability, 4-feat, 3-item) +// Type 1)spell 0-type, 1-spell, 2-class, 3-level, 4-slot. +// Type 2)sp Ability 0-type, 1-spell, 2-class, 3-level, 4-slot. +// Type 3)feat 0-type, 1-spell, 2- class, 3- level. +// Type 4)item 0-type, 1-spell, 2-item object, 3-level, 4-slot. +// jJsonLevel is the level to place the talent in the json array +// maybe different then the talents actual level which is passed in nLevel. +void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bBuff, object oItem = OBJECT_INVALID); +// Removes a talent nSlotIndex from jLevel in jCategory. +void ai_RemoveTalent(object oCreature, json jCategory, json jLevel, string sCategory, int nLevel, int nSlotIndex); +// Saves a creatures talents to variables upon them for combat use. +// bMonster will check to see if they should be buffed when we set the talents. +void ai_SetCreatureTalents(object oCreature, int bMonster); +// Return TRUE if oCreature spontaneously casts a cure spell from a talent in sCategory. +int ai_UseSpontaneousCureTalentFromCategory(object oCreature, string sCategory, int nInMelee, int nDamage, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses jTalent on oTarget. +// also Returns -1 if oCreature uses jTalent on oTarget with a memorized spell. +// This allows the user to remove jTalent from jLevel in jCategory. +int ai_UseCreatureSpellTalent(object oCreature, json jLevel, json jTalent, string sCategory, int nInMelee, object oTarget = OBJECT_INVALID); +// Return TRUE if oCreature uses a jTalent from oItem on oTarget. +int ai_UseCreatureItemTalent(object oCreature, json jLevel, json jTalent, string sCategory, int nInMelee, object oTarget = OBJECT_INVALID); +// Returns TRUE if oCreature uses a talent from sCategory of nLevel or less. +int ai_UseCreatureTalent(object oCreature, string sCategory, int nInMelee, int nLevel = 10, object oTarget = OBJECT_INVALID); +// Return TRUE if oCreature uses nTalent on oTarget. +int ai_UseTalent(object oCreature, int nTalent, object oTarget); +// Returns TRUE if jTalent is used on oTarget by oCaster. +// Checks the talent type and casts the correct spell. For items it checks uses. +int ai_UseTalentOnObject(object oCaster, json jTalent, object oTarget, int nInMelee); +// Returns TRUE if jTalent is used at lTarget location by oCaster. +// Checks the talent type and cast the correct spell. For items it checks uses. +int ai_UseTalentAtLocation(object oCaster, json jTalent, object oTarget, int nInMelee); +// Return TRUE if oCreature uses jTalent on oTarget after checking special cases. +int ai_CheckSpecialTalentsandUse(object oCreature, json jTalent, string sCategory, int nInMelee, object oTarget); + +int ai_TryHealingTalent(object oCreature, int nInMelee, object oTarget = OBJECT_INVALID) +{ + // First lets evaluate oTarget and see how strong of a spell we will need. + if(oTarget != OBJECT_INVALID) + { + if(oTarget == oCreature) + { + if(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF)) return FALSE; + } + else if(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) return FALSE; + } + // We don't have a target so lets go check for one. + else + { + if(!ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) + { + // Lets not run past an enemy to heal unless we have the feats, bad tactics! + float fRange; + if(ai_CanIMoveInCombat(oCreature)) fRange = AI_RANGE_PERCEPTION; + else + { + fRange = GetDistanceBetween(oCreature, GetLocalObject(oCreature, AI_ENEMY_NEAREST)) - 3.0f; + // Looks bad when your right next to an ally, but technically the enemy is closer. + if(fRange < AI_RANGE_MELEE) fRange = AI_RANGE_MELEE; + } + oTarget = ai_GetAllyToHealTarget(oCreature, fRange); + } + else oTarget = oCreature; + if(oTarget == OBJECT_INVALID) return FALSE; + } + // Should we ignore associates? + if(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + int nHp = ai_GetPercHPLoss(oTarget); + int nHpLimit = ai_GetHealersHpLimit(oCreature); + if(AI_DEBUG) ai_Debug("0i_talents", "256", "nHp: " + IntToString(nHp) + + "< nHpLimit: " + IntToString(nHpLimit)); + if(nHp > nHpLimit) return FALSE; + int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "260", GetName(oTarget) + " has lost " + IntToString(nDamage) + " hitpoints!"); + // Do they have Lay on Hands? + int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC); + if(bUseMagic && GetHasFeat(FEAT_LAY_ON_HANDS, oCreature)) + { + int nCanHeal = GetAbilityModifier(ABILITY_CHARISMA, oCreature) * ai_GetCharacterLevels(oCreature); + if(nCanHeal <= nDamage) + { + ai_UseFeat(oCreature, FEAT_LAY_ON_HANDS, oTarget); + return TRUE; + } + } + int nMaxLevel = 9; + // If they are about to die then throw caution to the wind and HEAL! + if(nHp <= AI_HEALTH_BLOODY || nHp < 11) nInMelee = 0; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_HEALING, nInMelee, nMaxLevel, oTarget)) return TRUE; + if(AI_DEBUG) ai_Debug("0i_talents", "275", GetName(oCreature) + " has no healing spells!" + + " Cleric lvls: " + IntToString(GetLevelByClass(CLASS_TYPE_CLERIC, oCreature)) + + " Sontaneous casting: " + IntToString(ai_GetMagicMode(oCreature, AI_MAGIC_NO_SPONTANEOUS_CURE))); + if(bUseMagic && GetLevelByClass(CLASS_TYPE_CLERIC, oCreature) && + !ai_GetMagicMode(oCreature, AI_MAGIC_NO_SPONTANEOUS_CURE)) + { + // We need to check our talents and see what spells we can convert. + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_ENHANCEMENT, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_PROTECTION, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_TOUCH, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_RANGED, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_SUMMON, nInMelee, nDamage, oTarget)) return TRUE; + if(ai_UseSpontaneousCureTalentFromCategory(oCreature, AI_TALENT_CURE, nInMelee, nDamage, oTarget)) return TRUE; + } + return FALSE; +} +int ai_CheckTargetVsConditions(object oTarget, json jTalent, int nConditions) +{ + // Check nCondition for any negative effects based on the talent we have. + switch(JsonGetInt(JsonArrayGet(jTalent, 1))) + { + case SPELL_NEUTRALIZE_POISON : + if(ai_GetHasNegativeCondition(AI_CONDITION_POISON, nConditions)) return TRUE; + break; + case SPELL_REMOVE_DISEASE : + if(ai_GetHasNegativeCondition(AI_CONDITION_DISEASE, nConditions)) return TRUE; + break; + case SPELL_REMOVE_BLINDNESS_AND_DEAFNESS : + if(ai_GetHasNegativeCondition(AI_CONDITION_BLINDDEAF, nConditions)) return TRUE; + break; + case SPELL_REMOVE_FEAR : + if(ai_GetHasNegativeCondition(AI_CONDITION_FRIGHTENED, nConditions)) return TRUE; + break; + case SPELL_REMOVE_CURSE : + if(ai_GetHasNegativeCondition(AI_CONDITION_CURSE, nConditions)) return TRUE; + break; + case SPELL_REMOVE_PARALYSIS : + if(ai_GetHasNegativeCondition(AI_CONDITION_PARALYZE, nConditions)) return TRUE; + break; + case SPELL_CLARITY : + if(ai_GetHasNegativeCondition(AI_CONDITION_DAZED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_CHARMED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_CONFUSED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_STUNNED, nConditions)) return TRUE; + break; + case SPELL_GREATER_RESTORATION : + if(ai_GetHasNegativeCondition(AI_CONDITION_DAZED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_CONFUSED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_DOMINATED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_SLOW, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_FRIGHTENED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_STUNNED, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_CHARMED, nConditions)) return TRUE; + case SPELL_RESTORATION : + if(ai_GetHasNegativeCondition(AI_CONDITION_LEVEL_DRAIN, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_BLINDDEAF, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_PARALYZE, nConditions)) return TRUE; + case SPELL_LESSER_RESTORATION : + if(ai_GetHasNegativeCondition(AI_CONDITION_ABILITY_DRAIN, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_SAVE_DECREASE, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_SR_DECREASE, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_SKILL_DECREASE, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_AC_DECREASE , nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_ATK_DECREASE, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_DMG_DECREASE, nConditions)) return TRUE; + if(ai_GetHasNegativeCondition(AI_CONDITION_DMG_I_DECREASE, nConditions)) return TRUE; + } + return FALSE; +} +int ai_CheckTalentsVsConditions(object oCreature, int nConditions, int nInMelee, int nLevel, object oTarget) +{ + // Get the saved category from oCreature. + json jCategory = GetLocalJson(oCreature, AI_TALENT_CURE); + if(AI_DEBUG) ai_Debug("0i_talents", "357", "jCategory: " + AI_TALENT_CURE + " " + JsonDump(jCategory, 2)); + if(JsonGetType(jCategory) == JSON_TYPE_NULL) + { + SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE, -1); + return FALSE; + } + // Get the max talent level so we can skip the higher ones and save time. + int nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE); + if(AI_DEBUG) ai_Debug("0i_talents", "365", AI_MAX_TALENT + AI_TALENT_CURE + ": " + + IntToString(nMaxTalentLevel) + + " nLevel: " + IntToString(nLevel)); + if(nMaxTalentLevel < nLevel) nLevel = nMaxTalentLevel; + if(nLevel < 0 || nLevel > 10) nLevel = 9; + json jLevel, jTalent; + int nClass, nSlot, nType, nSlotIndex, nMaxSlotIndex, nTalentUsed; + int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC); + int bUseMagicItems = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC_ITEMS); + if(AI_DEBUG) ai_Debug("0i_talents", "374", "bUseMagic: " + IntToString(bUseMagic) + + " bUseMagicItems: " + IntToString(bUseMagicItems)); + // Loop through nLevels down to 0 looking for the first talent (i.e. the highest). + while(nLevel >= 0) + { + // Get the array of nLevel cycling down to 0. + jLevel = JsonArrayGet(jCategory, nLevel); + nMaxSlotIndex = JsonGetLength(jLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "382", "nLevel: " + IntToString(nLevel) + + " nMaxSlotIndex: " + IntToString(nMaxSlotIndex)); + if(nMaxSlotIndex > 0) + { + // Get the talent within nLevel cycling from the first to the last. + nSlotIndex = 0; + while (nSlotIndex <= nMaxSlotIndex) + { + jTalent= JsonArrayGet(jLevel, nSlotIndex); + if(AI_DEBUG) ai_Debug("0i_talents", "391", "nSlotIndex: " + IntToString(nSlotIndex) + + " jTalent Type: " + IntToString(JsonGetType(jTalent))); + // Check to see if the talent matches oTargets nConditionss. + if(ai_CheckTargetVsConditions(oTarget, jTalent, nConditions)) + { + nType = JsonGetInt(JsonArrayGet(jTalent, 0)); + if(bUseMagic) + { + if(nType == AI_TALENT_TYPE_SPELL) + { + if(ai_CastInMelee(oCreature, JsonGetInt(JsonArrayGet(jTalent, 1)), nInMelee)) + { + nTalentUsed = ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, AI_TALENT_CURE, nInMelee, oTarget); + // -1 means it was a memorized spell and we need to remove it. + if(nTalentUsed == -1) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, AI_TALENT_CURE, nLevel, nSlotIndex); + return TRUE; + } + else if(nTalentUsed) return TRUE; + } + } + else if(nType == AI_TALENT_TYPE_SP_ABILITY) + { + // Special ability spells do not need to concentrate?! + if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, AI_TALENT_CURE, nInMelee, oTarget)) + { + // When the ability is used that slot is now not readied. + // Multiple uses of the same spell are stored in different slots. + ai_RemoveTalent(oCreature, jCategory, jLevel, AI_TALENT_CURE, nLevel, nSlotIndex); + return TRUE; + } + } + } + if(bUseMagicItems && nType == AI_TALENT_TYPE_ITEM) + { + // Items do not need to concentrate. + if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, AI_TALENT_CURE, nInMelee, oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_talents", "430", "Checking if Item is used up: " + + IntToString(JsonGetInt(JsonArrayGet(jTalent, 4)))); + if(JsonGetInt(JsonArrayGet(jTalent, 4)) == -1) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, AI_TALENT_CURE, nLevel, nSlotIndex); + } + return TRUE; + } + } + } + nSlotIndex++; + } + } + else SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE, nLevel - 1); + nLevel--; + } + return FALSE; +} +int ai_TryCureConditionTalent(object oCreature, int nInMelee, object oTarget = OBJECT_INVALID) +{ + // Is Casting Cure spells off? + if(ai_GetMagicMode(oCreature, AI_MAGIC_CURE_SPELLS_OFF)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "450", AI_MAX_TALENT + AI_TALENT_CURE + ": " + + IntToString(GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE))); + // If the creature doesn't have cure talents then we set it to -1. + if(GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE) == -1) return FALSE; + // We check targets to see if they need to be cured. + int nNegativeConditions, nTargetNegConds, nIndex, nCnt = 1; + object oTarget; + if(oTarget == OBJECT_INVALID) + { + oTarget = GetLocalObject(oCreature, AI_ALLY + "1"); + while(oTarget != OBJECT_INVALID) + { + nTargetNegConds = ai_GetNegativeConditions(oTarget); + // Should we ignore associates? + if(!ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) || + GetAssociateType(oTarget) < 2) + { + if(nNegativeConditions < nTargetNegConds) + { + nNegativeConditions = nTargetNegConds; + nIndex = nCnt; + } + } + oTarget = GetLocalObject(oCreature, AI_ALLY + IntToString(++nCnt)); + } + // No one has a negative condition then get out. + if(!nNegativeConditions) return FALSE; + oTarget = GetLocalObject(oCreature, AI_ALLY + IntToString(nIndex)); + } + else + { + nNegativeConditions = ai_GetNegativeConditions(oTarget); + if(!nNegativeConditions) return FALSE; + } + if(oTarget == oCreature) + { + if(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF)) return FALSE; + } + else if(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "489", "nNegativeConditions: " + IntToString(nNegativeConditions) + + " on " + GetName(oTarget)); + if(ai_CheckTalentsVsConditions(oCreature, nNegativeConditions, nInMelee, 9, oTarget)) return TRUE; + return FALSE; +} +// ***************************************************************************** +// ************************* Try * Defensive Talents *************************** +// ***************************************************************************** +// These functions try to find and use a specific set of talents intelligently. + +int ai_TryDefensiveTalents(object oCreature, int nInMelee, int nMaxLevel, int nRound = 0, object oTarget = OBJECT_INVALID) +{ + // Summons are powerfull and should be used as much as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_SUMMON, nInMelee, nMaxLevel, oTarget)) return TRUE; + // Added to reduce casting defensive talents later in combat and constantly. + if(nRound >= d8()) return FALSE; + // Try to mix them up so we don't always cast spells in the same order. + int nRoll = d2(); + if(AI_DEBUG) ai_Debug("0i_talents", "507", "Lets help someone(Check Talents: " +IntToString(nRoll) + + " nMaxLevel: " + IntToString(nMaxLevel) + ")!"); + if(nRoll == 1) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_ENHANCEMENT, nInMelee, nMaxLevel, oTarget)) return TRUE; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_PROTECTION, nInMelee, nMaxLevel, oTarget)) return TRUE; + } + else if(nRoll == 2) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_PROTECTION, nInMelee, nMaxLevel, oTarget)) return TRUE; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_ENHANCEMENT, nInMelee, nMaxLevel, oTarget)) return TRUE; + } + return FALSE; +} +void ai_SetAura(object oCreature) +{ + // Cycle through a creatures special abilities and use any auras. + int bCanUse, nIndex = 0, nMaxSpAbility = GetSpellAbilityCount(oCreature); + int nSpell = GetSpellAbilitySpell(oCreature, nIndex); + while(nIndex < nMaxSpAbility) + { + bCanUse = FALSE; + if(GetSpellAbilityReady(oCreature, nIndex)) + { + if(nSpell == SPELLABILITY_AURA_BLINDING) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_COLD) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_ELECTRICITY) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_FEAR) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_FIRE) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_HORRIFICAPPEARANCE) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_MENACE) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_HORRIFICAPPEARANCE) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_PROTECTION) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_STUN) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_UNEARTHLY_VISAGE) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_UNNATURAL) bCanUse = TRUE; + else if(nSpell == SPELLABILITY_AURA_HORRIFICAPPEARANCE) bCanUse = TRUE; + else if(nSpell == 306 /*SPELLABILITY_AURA_TYRANT_FOG_MIST*/) bCanUse = TRUE; + else if(nSpell == 412 /*SPELLABILITY_AURA_DRAGON_FEAR*/) bCanUse = TRUE; + else if(nSpell == 761 /*SPELLABILITY_AURA_HELLFIRE*/) bCanUse = TRUE; + else if(nSpell == 805/*SPELLABILITY_AURA_TROGLODYTE_STENCH*/) bCanUse = TRUE; + } + if(bCanUse) ActionCastSpellAtObject(nSpell, oCreature, 255, FALSE, 0, 0, TRUE); + nSpell = GetSpellAbilitySpell(oCreature, ++nIndex); + } +} +// ***************************************************************************** +// ************************* Try * Skills ************************************** +// ***************************************************************************** +// These functions try to find and use a specific set of skills intelligently. + +void ai_UseSkill(object oCreature, int nSkill, object oTarget) +{ + ai_SetLastAction(oCreature, AI_LAST_ACTION_USED_SKILL); + if(GetIsEnemy(oTarget, oCreature)) SetLocalObject(oCreature, AI_ATTACKED_PHYSICAL, oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "498", GetName(oCreature) + " is using skill: " + + GetStringByStrRef(StringToInt(Get2DAString("skills", "Name", nSkill))) + + " on " + GetName(oTarget)); + ActionUseSkill(nSkill, oTarget); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); +} +int ai_TryParry(object oCreature) +{ + // Only use parry on an active melee attacker + object oTarget = GetLastHostileActor(oCreature); + // If we are already in parry mode then lets keep it up. + if(GetActionMode(oCreature, ACTION_MODE_PARRY) && + GetCurrentAction(oCreature) == ACTION_ATTACKOBJECT) return TRUE; + if(oTarget == OBJECT_INVALID || + ai_GetAttackedTarget(oTarget) != oCreature || + !ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget))) return FALSE; + // Only if our parry skill > their attack bonus + 5 + d10 + // Parry has a -4 atk adjustment. Our chance to hit should be 75% + d10. + // EnemyAtk(20) - OurParrySkill(10) = 0 + d10(75% to 25% chance to hit). + int nParrySkill = GetSkillRank(SKILL_PARRY, oCreature); + int nAtk = ai_GetCreatureAttackBonus(oTarget); + if(nAtk - nParrySkill >= 0 + d10()) return FALSE; + ai_EquipBestMeleeWeapon(oCreature, oTarget); + SetActionMode(oCreature, ACTION_MODE_PARRY, TRUE); + ai_SetLastAction(oCreature, AI_LAST_ACTION_USED_SKILL); + ActionAttack(oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "524", "Using parry against " + GetName(oTarget) + "!"); + return TRUE; +} +int ai_TryTaunt(object oCreature, object oTarget) +{ + int nCoolDown = GetLocalInt(oCreature, "AI_TAUNT_COOLDOWN"); + if(AI_DEBUG) ai_Debug("0i_talents", "530", "Has Taunt Effect? " + + IntToString(ai_GetHasEffectType(oTarget, EFFECT_TYPE_TAUNT)) + + " Cooldown: " + IntToString(nCoolDown)); + if(nCoolDown > 0) + { + SetLocalInt(oCreature, "AI_TAUNT_COOLDOWN", --nCoolDown); + return FALSE; + } + if(!ai_GetHasEffectType(oTarget, EFFECT_TYPE_TAUNT)) return FALSE; + // Check to see if we have a good chance for it to work. + int nTauntRnk = GetSkillRank(SKILL_TAUNT, oCreature); + if(AI_DEBUG) ai_Debug("0i_talents", "542", "Check Taunt: TauntRnk: " + IntToString(nTauntRnk) + + " HitDice + 1: " + IntToString(GetHitDice(oCreature) + 1) + + " Concentration: " + IntToString(GetSkillRank(SKILL_CONCENTRATION, oTarget)) + "."); + int nConcentration = GetSkillRank(SKILL_CONCENTRATION, oTarget); + // Our chance is greater than 50%. + if(nTauntRnk <= nConcentration) return FALSE; + ai_UseSkill(oCreature, SKILL_TAUNT, oTarget); + SetLocalInt(oCreature, "AI_TAUNT_COOLDOWN", AI_TAUNT_COOLDOWN); + return TRUE; +} +int ai_TryAnimalEmpathy(object oCreature, object oTarget = OBJECT_INVALID) +{ + if(!GetSkillRank(SKILL_ANIMAL_EMPATHY, oCreature)) return FALSE; + int nCoolDown = GetLocalInt(oCreature, "AI_EMPATHY_COOLDOWN"); + if(AI_DEBUG) ai_Debug("0i_talents", "556", "Has Dominate Effect? " + + IntToString(ai_GetHasEffectType(oTarget, EFFECT_TYPE_DOMINATED)) + + " Cooldown: " + IntToString(nCoolDown)); + if(nCoolDown > 0) + { + SetLocalInt(oCreature, "AI_EMPATHY_COOLDOWN", --nCoolDown); + return FALSE; + } + if(oTarget == OBJECT_INVALID) + { + oTarget = ai_GetNearestRacialTarget(oCreature, AI_RACIAL_TYPE_ANIMAL_BEAST); + if(oTarget == OBJECT_INVALID) return FALSE; + } + if(!GetObjectSeen(oCreature, oTarget)) return FALSE; + if(ai_GetHasEffectType(oTarget, EFFECT_TYPE_DOMINATED) || + GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS) || + GetIsImmune(oTarget, IMMUNITY_TYPE_DOMINATE) || + GetAssociateType(oTarget) != ASSOCIATE_TYPE_NONE) return FALSE; + // Get the race of the target, it only works on Animals, Beasts, and Magical Beasts. + int nRace = GetRacialType(oTarget); + int nDC; + if(nRace == RACIAL_TYPE_ANIMAL) nDC = 5; + else if(nRace == RACIAL_TYPE_BEAST || nRace == RACIAL_TYPE_MAGICAL_BEAST) nDC = 9; + else return FALSE; + // Check to see if we have a good chance for it to work. + int nEmpathyRnk = GetSkillRank(SKILL_ANIMAL_EMPATHY, oCreature); + nDC += GetHitDice(oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "632", "Check Animal Empathy: Rnk: " + IntToString(nEmpathyRnk) + + " nDC: " + IntToString(nDC) + "."); + // Our chance is greater than 50%. + if(nEmpathyRnk <= nDC) return FALSE; + ai_UseSkill(oCreature, SKILL_ANIMAL_EMPATHY, oTarget); + SetLocalInt(oCreature, "AI_EMPATHY_COOLDOWN", AI_EMPATHY_COOLDOWN); + return TRUE; +} +// ***************************************************************************** +// ************************* Try * Feats *************************************** +// ***************************************************************************** +// These functions try to find and use a specific set of feats intelligently. + +void ai_UseFeat(object oCreature, int nFeat, object oTarget, int nSubFeat = 0) +{ + ai_SetLastAction(oCreature, AI_LAST_ACTION_USED_FEAT); + if(GetIsEnemy(oTarget, oCreature)) SetLocalObject(oCreature, AI_ATTACKED_PHYSICAL, oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "600", GetName(oCreature) + " is using feat: " + + GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))) + + " on " + GetName(oTarget)); + ActionUseFeat(nFeat, oTarget, nSubFeat); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); +} +void ai_UseFeatAttackMode(object oCreature, int nActionMode, int nAction, object oTarget, int nInMelee = 0, int bPassive = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "608", "Action mode (" + IntToString(nActionMode) + ") Is it set?: " + + IntToString(GetActionMode(oCreature, nActionMode))); + if(!GetActionMode(oCreature, nActionMode)) + { + if(AI_DEBUG) ai_Debug("0i_talents", "612", "Setting action mode: " + IntToString(nActionMode)); + SetActionMode(oCreature, nActionMode, TRUE); + SetLocalInt(oCreature, AI_CURRENT_ACTION_MODE, nActionMode); + } + ai_ActionAttack(oCreature, nAction, oTarget, nInMelee, bPassive, nActionMode); +} +int ai_TryBarbarianRageFeat(object oCreature) +{ + // Must not have rage already, must have the feat, and enemy must be strong enough. + if(GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) || + !GetHasFeat(FEAT_BARBARIAN_RAGE, oCreature)) return FALSE; + ai_UseFeat(oCreature, FEAT_BARBARIAN_RAGE, oCreature); + return TRUE; +} +int ai_TryBardSongFeat(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "629", "BardSong Effect: " + IntToString(GetHasSpellEffect(411/*SPELL_BARD_SONG*/)) + + " Level: " + IntToString(GetLevelByClass(CLASS_TYPE_BARD)) + + " HasFeat: " + IntToString(GetHasFeat(FEAT_BARD_SONGS))); + if(GetHasSpellEffect(411/*SPELL_BARD_SONG*/, oCreature) || + !GetHasFeat(FEAT_BARD_SONGS, oCreature)) return FALSE; + ai_UseFeat(oCreature, FEAT_BARD_SONGS, oCreature); + return TRUE; +} +int ai_TryCalledShotFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_CALLED_SHOT, oCreature)) return FALSE; + // Called shot has a -4 to hit adjustment. + if(!ai_AttackPenaltyOk(oCreature, oTarget, -4.0)) return FALSE; + ai_UseFeat(oCreature, FEAT_CALLED_SHOT, oTarget); + return TRUE; +} +int ai_TryDisarmFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_DISARM, oCreature)) return FALSE; + // If we can't disarm them then get out! + if(!GetIsCreatureDisarmable(oTarget)) return FALSE; + int nEAC = GetAC(oTarget); + int nOAtk = ai_GetCreatureAttackBonus(oCreature); + // The combatant with the larger weapon gains +4 per size category. + // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large. + int nOWeaponType = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND)); + int nOWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nOWeaponType)); + int nEWeaponType = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget)); + int nEWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nEWeaponType)); + nOAtk +=(nOWeaponSize - nEWeaponSize) * 4; + // Do they have Improved Disarm? + if(GetHasFeat(FEAT_IMPROVED_DISARM, oCreature)) nOAtk += 2; + // Disarm has a -6 atk adjustment. + if(!ai_AttackPenaltyOk(oCreature, oTarget, -6.0)) return FALSE; + ai_UseFeat(oCreature, FEAT_DISARM, oTarget); + return TRUE; +} +int ai_TryDivineMightFeat(object oCreature, int nInMelee) +{ + if(!GetHasFeat(FEAT_TURN_UNDEAD)) return FALSE; + if(!GetHasFeat(FEAT_DIVINE_MIGHT)) return FALSE; + if(GetHasFeatEffect(FEAT_DIVINE_MIGHT, oCreature)) return FALSE; + if(!nInMelee) return FALSE; + object oTarget = ai_GetEnemyAttackingMe(oCreature); + if(oTarget == OBJECT_INVALID) return FALSE; + float fAtkAdj = IntToFloat(GetAbilityModifier(ABILITY_CHARISMA, oCreature)); + if(!ai_AttackBonusGood(oCreature, oTarget, fAtkAdj)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "722", "USING DIVINE MIGHT on " + GetName(oCreature) + "."); + ai_UseFeat(oCreature, FEAT_DIVINE_MIGHT, oCreature); + return TRUE; +} +int ai_TryDivineShieldFeat(object oCreature, int nInMelee) +{ + if(!GetHasFeat(FEAT_TURN_UNDEAD)) return FALSE; + if(!GetHasFeat(FEAT_DIVINE_SHIELD)) return FALSE; + if(GetHasFeatEffect(FEAT_DIVINE_SHIELD, oCreature)) return FALSE; + if(!nInMelee) return FALSE; + object oTarget = ai_GetEnemyAttackingMe(oCreature); + if(oTarget == OBJECT_INVALID) return FALSE; + float fACAdj = IntToFloat(GetAbilityModifier(ABILITY_CHARISMA, oCreature)); + if(!ai_ACAdjustmentGood(oCreature, oTarget, fACAdj)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "736", "USING DIVINE SHIELD on " + GetName(oCreature) + "."); + ai_UseFeat(oCreature, FEAT_DIVINE_SHIELD, oCreature); + return TRUE; +} +int ai_TryExpertiseFeat(object oCreature) +{ + if(!GetHasFeat(FEAT_EXPERTISE, oCreature)) return FALSE; + object oTarget = ai_GetEnemyAttackingMe(oCreature); + // Expertise has a -5 atk and a +5 AC adjustment. + if(oTarget == OBJECT_INVALID || + !ai_AttackPenaltyOk(oCreature, oTarget, -5.0) || + !ai_ACAdjustmentGood(oCreature, oTarget, 5.0)) + { + SetActionMode(oCreature, ACTION_MODE_EXPERTISE, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "704", "USING EXPERTISE on " + GetName(oTarget) + "."); + ai_UseFeatAttackMode(oCreature, ACTION_MODE_EXPERTISE, AI_LAST_ACTION_MELEE_ATK, oTarget); + return TRUE; +} +int ai_TryFlurryOfBlowsFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_FLURRY_OF_BLOWS, oCreature)) return FALSE; + // Flurry of Blows has a -2 atk adjustment. + if(!ai_AttackPenaltyOk(oCreature, oTarget, -2.0)) + { + SetActionMode(oCreature, ACTION_MODE_FLURRY_OF_BLOWS, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "718", "USING FLURRY OF BLOWS on " + GetName(oTarget) + "."); + ai_UseFeatAttackMode(oCreature, ACTION_MODE_FLURRY_OF_BLOWS, AI_LAST_ACTION_MELEE_ATK, oTarget, TRUE); + return TRUE; +} +int ai_TryImprovedExpertiseFeat(object oCreature) +{ + if(!GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature)) return FALSE; + object oTarget = ai_GetEnemyAttackingMe(oCreature); + // Improved expertise has a -10 atk +10 AC adjustment. + if(oTarget == OBJECT_INVALID || + !ai_AttackPenaltyOk(oCreature, oTarget, -10.0) || + !ai_ACAdjustmentGood(oCreature, oTarget, 10.0)) + { + SetActionMode(oCreature, ACTION_MODE_IMPROVED_EXPERTISE, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "735", "USING IMPROVED EXPERTISE on " + GetName(oTarget) + "."); + ai_UseFeatAttackMode(oCreature, ACTION_MODE_IMPROVED_EXPERTISE, AI_LAST_ACTION_MELEE_ATK, oTarget); + return TRUE; +} +int ai_TryImprovedPowerAttackFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_IMPROVED_POWER_ATTACK, oCreature)) return FALSE; + // Improved Power Attack has a -10 atk adjustment. + // If we cannot hit or will kill in one hit then maybe we should use Power Attack instead. + if(ai_PowerAttackGood(oCreature, oTarget, 10.0)) + { + ai_UseFeatAttackMode(oCreature, ACTION_MODE_IMPROVED_POWER_ATTACK, AI_LAST_ACTION_MELEE_ATK, oTarget); + return TRUE; + } + SetActionMode(oCreature, ACTION_MODE_IMPROVED_POWER_ATTACK, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return ai_TryPowerAttackFeat(oCreature, oTarget); +} +int ai_TryKiDamageFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_KI_DAMAGE, oCreature)) return FALSE; + // Must have > 40 hitpoints AND + // Damage reduction OR damage resistance + // or just have over 200 hitpoints + int bHasDamageReduction = FALSE; + int bHasDamageResistance = FALSE; + int bHasHitpoints = FALSE; + int bHasMassiveHitpoints = FALSE; + int bOutNumbered; + int nCurrentHP = GetCurrentHitPoints(oTarget); + if(nCurrentHP > 40) bHasHitpoints = TRUE; + if(nCurrentHP > 200) bHasMassiveHitpoints = TRUE; + if(ai_GetHasEffectType(oTarget, EFFECT_TYPE_DAMAGE_REDUCTION)) bHasDamageReduction = TRUE; + if(ai_GetHasEffectType(oTarget, EFFECT_TYPE_DAMAGE_RESISTANCE)) bHasDamageResistance = TRUE; + if(ai_GetNearestEnemy(oCreature, 3, 7, 7) != OBJECT_INVALID) bOutNumbered = TRUE; + if((!bHasHitpoints || (!bHasDamageReduction && !bHasDamageResistance)) && + (!bHasMassiveHitpoints) && (!bHasHitpoints || !bOutNumbered)) return FALSE; + ai_UseFeat(oCreature, FEAT_KI_DAMAGE, oTarget); + return TRUE; +} +int ai_TryKnockdownFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_KNOCKDOWN, oCreature)) return FALSE; + int nMySize = GetCreatureSize(oCreature); + if(GetHasFeat(FEAT_IMPROVED_KNOCKDOWN, oCreature)) nMySize++; + // Prevent silly use of knockdown on immune or too-large targets. + // Knockdown has a -4 atk adjustment. + if(GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN) || + GetCreatureSize(oTarget) > nMySize + 1 || + !ai_AttackPenaltyOk(oCreature, oTarget, -4.0)) return FALSE; + ai_UseFeat(oCreature, FEAT_KNOCKDOWN, oTarget); + return TRUE; +} +int ai_TryPolymorphSelfFeat(object oCreature) +{ + if(GetHasFeat(FEAT_EPIC_OUTSIDER_SHAPE)) + { + int nSubFeat = Random(3) + 733; // 733 azer, 734 rakshasa, 735 Slaad. + if(ai_UseFeat(oCreature, FEAT_EPIC_OUTSIDER_SHAPE, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_EPIC_CONSTRUCT_SHAPE)) + { + int nSubFeat = Random(3) + 738; // 738 Stone, 739 Flesh, 740 Iron. + if(ai_UseFeat(oCreature, FEAT_EPIC_CONSTRUCT_SHAPE, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_EPIC_WILD_SHAPE_DRAGON)) + { + int nSubFeat = Random(3) + 707; // 707 Red, 708 Blue, 709 Green. + if(ai_UseFeat(oCreature, FEAT_EPIC_WILD_SHAPE_DRAGON, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_EPIC_WILD_SHAPE_UNDEAD)) + { + int nSubFeat = Random(3) + 704; // 704 Risen Lord, 705 Vampire, 706 Spectre. + if(ai_UseFeat(oCreature, FEAT_EPIC_WILD_SHAPE_UNDEAD, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_GREATER_WILDSHAPE_4)) + { + int nSubFeat; + int nRoll = d3(); + if(nRoll == 1) nSubFeat = 679; // Medusa + else if(nRoll == 2) nSubFeat = 691; // Mindflayer + else nSubFeat = 694; // DireTiger + if(ai_UseFeat(oCreature, FEAT_GREATER_WILDSHAPE_4, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_GREATER_WILDSHAPE_3)) + { + int nSubFeat; + int nRoll = d3(); + if(nRoll == 1) nSubFeat = 670; // Basilisk + else if(nRoll == 2) nSubFeat = 673; // Drider + else nSubFeat = 674; // Manticore + if(ai_UseFeat(oCreature, FEAT_GREATER_WILDSHAPE_3, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_GREATER_WILDSHAPE_2)) + { + int nSubFeat; + int nRoll = d3(); + if(nRoll == 1) nSubFeat = 672; // Harpy + else if(nRoll == 2) nSubFeat = 678; // Gargoyle + else nSubFeat = 680; // Minotaur + if(ai_UseFeat(oCreature, FEAT_GREATER_WILDSHAPE_2, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_GREATER_WILDSHAPE_1)) + { + int nSubFeat = Random(5) + 658; // Wyrmling + if(ai_UseFeat(oCreature, FEAT_GREATER_WILDSHAPE_1, oCreature, nSubFeat)) return TRUE; + } + if(GetHasFeat(FEAT_HUMANOID_SHAPE)) + { + int nSubFeat = Random(3) + 682; // 682 Drow, 683 Lizard, 684 Kobold. + if(ai_UseFeat(oCreature, FEAT_HUMANOID_SHAPE, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_ELEMENTAL_SHAPE)) + { + int nSubFeat = Random(4) + SUBFEAT_ELEMENTAL_SHAPE_EARTH; + if(ai_UseFeat(oCreature, FEAT_ELEMENTAL_SHAPE, oCreature, nSubFeat)) return TRUE; + } + else if(GetHasFeat(FEAT_WILD_SHAPE)) + { + int nSubFeat; + int nCompanionType = GetAnimalCompanionCreatureType(oCreature); + if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_NONE) + nSubFeat = Random(5) + SUBFEAT_WILD_SHAPE_BROWN_BEAR; + else + { + if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_BADGER) + nSubFeat = SUBFEAT_WILD_SHAPE_BADGER; + else if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_BOAR) + nSubFeat = SUBFEAT_WILD_SHAPE_BOAR; + else if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_BEAR) + nSubFeat = SUBFEAT_WILD_SHAPE_BROWN_BEAR; + else if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_PANTHER) + nSubFeat = SUBFEAT_WILD_SHAPE_PANTHER; + else if(nCompanionType == ANIMAL_COMPANION_CREATURE_TYPE_WOLF) + nSubFeat = SUBFEAT_WILD_SHAPE_WOLF; + else nSubFeat = Random(5) + SUBFEAT_WILD_SHAPE_BROWN_BEAR; + } + if(AI_DEBUG) ai_Debug("0i_talents", "885", " Using wild shape feat: " + IntToString(nSubFeat)); + ai_UseFeat(oCreature, FEAT_WILD_SHAPE, oCreature, nSubFeat); + return TRUE; + } + return FALSE; +} +int ai_TryPowerAttackFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_POWER_ATTACK, oCreature)) return FALSE; + // Power Attack has a -5 atk adjustment. + if(ai_PowerAttackGood(oCreature, oTarget, 5.0)) + { + ai_UseFeatAttackMode(oCreature, ACTION_MODE_POWER_ATTACK, AI_LAST_ACTION_MELEE_ATK, oTarget); + return TRUE; + } + SetActionMode(oCreature, ACTION_MODE_POWER_ATTACK, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return FALSE; +} +int ai_TryQuiveringPalmFeat(object oCreature, object oTarget) +{ + // Must have the feat, and enemy must be lower level, and not immune to crits. + if(!GetHasFeat(FEAT_QUIVERING_PALM, oCreature) || + GetHitDice(oTarget) >= GetHitDice(oCreature) || + GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) return FALSE; + ai_UseFeat(oCreature, FEAT_QUIVERING_PALM, oTarget); + return TRUE; +} +int ai_TryRapidShotFeat(object oCreature, object oTarget, int nInMelee) +{ + if(!GetHasFeat(FEAT_RAPID_SHOT, oCreature)) return FALSE; + // Rapidshot has a -4 atk adjustment. + if(!ai_AttackPenaltyOk(oCreature, oTarget, -4.0)) + { + SetActionMode(oCreature, ACTION_MODE_RAPID_SHOT, FALSE); + DeleteLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + return FALSE; + } + ai_UseFeatAttackMode(oCreature, ACTION_MODE_RAPID_SHOT, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return TRUE; +} +int ai_TrySapFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_SAP, oCreature)) return FALSE; + // Does not work on creatures that cannot be hit by criticals or stunned. + // Sap has a -4 atk adjustment. + if(GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT) || + GetIsImmune(oTarget, IMMUNITY_TYPE_STUN) || + !ai_AttackPenaltyOk(oCreature, oTarget, -4.0)) return FALSE; + ai_UseFeat(oCreature, FEAT_SAP, oTarget); + return TRUE; +} +int ai_TrySmiteEvilFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_SMITE_EVIL, oCreature) || + GetAlignmentGoodEvil(oTarget) != ALIGNMENT_EVIL || + !ai_StrongOpponent(oCreature, oTarget)) return FALSE; + ai_UseFeat(oCreature, FEAT_SMITE_EVIL, oTarget); + return TRUE; +} +int ai_TrySmiteGoodFeat(object oCreature, object oTarget) +{ + if(!GetHasFeat(FEAT_SMITE_GOOD, oCreature) || + GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD || + !ai_StrongOpponent(oCreature, oTarget)) return FALSE; + ai_UseFeat(oCreature, FEAT_SMITE_GOOD, oTarget); + return TRUE; +} +int ai_TryStunningFistFeat(object oCreature, object oTarget) +{ + // Cannot use if we have a weapon equiped. + if(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature) != OBJECT_INVALID) return FALSE; + // Does not work on creatures that cannot be hit by criticals or stunned. + // Stunning Fists has a -4 atk adjustment. + if(!GetHasFeat(FEAT_STUNNING_FIST, oCreature) || + GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT) || + GetIsImmune(oTarget, IMMUNITY_TYPE_STUN) || + !ai_StrongOpponent(oCreature, oTarget) || + !ai_AttackPenaltyOk(oCreature, oTarget, -4.0)) return FALSE; + ai_UseFeat(oCreature, FEAT_STUNNING_FIST, oTarget); + return TRUE; +} +void ai_NameAssociate(object oCreature, int nAssociateType, string sName) +{ + object oAssociate = GetAssociate(nAssociateType, oCreature); + if(GetName(oCreature) != "") return; + SetName(oAssociate, sName); + ChangeFaction(oAssociate, oCreature); +} +int ai_TrySummonAnimalCompanionTalent(object oCreature) +{ + if(!GetHasFeat(FEAT_ANIMAL_COMPANION, oCreature)) return FALSE; + if(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCreature) != OBJECT_INVALID) return FALSE; + ai_UseFeat(oCreature, FEAT_ANIMAL_COMPANION, oCreature); + DelayCommand(0.0, ai_NameAssociate(oCreature, ASSOCIATE_TYPE_FAMILIAR, "Animal Companion")); + return TRUE; +} +int ai_TrySummonFamiliarTalent(object oCreature) +{ + if(!GetHasFeat(FEAT_SUMMON_FAMILIAR, oCreature)) return FALSE; + if(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCreature) != OBJECT_INVALID) return FALSE; + ai_UseFeat(oCreature, FEAT_SUMMON_FAMILIAR, oCreature); + DelayCommand(0.0, ai_NameAssociate(oCreature, ASSOCIATE_TYPE_FAMILIAR, "Familiar")); + return TRUE; +} +int ai_TryLayOnHands(object oCreature) +{ + if(!GetHasFeat(FEAT_LAY_ON_HANDS, oCreature)) return FALSE; + // Lets not run past an enemy to use touch atk unless we have the feats, bad tactics! + float fRange; + if(ai_CanIMoveInCombat(oCreature)) fRange = AI_RANGE_PERCEPTION; + else + { + fRange = GetDistanceBetween(oCreature, GetLocalObject(oCreature, AI_ENEMY_NEAREST)) - 3.0f; + // Looks bad when your right next to an ally, but technically the enemy is closer. + if(fRange < AI_RANGE_MELEE) fRange = AI_RANGE_MELEE; + } + object oTarget = ai_GetLowestCRRacialTarget(oCreature, RACIAL_TYPE_UNDEAD, fRange); + if(oTarget == OBJECT_INVALID) return FALSE; + ai_UseFeat(oCreature, FEAT_LAY_ON_HANDS, oTarget); + return TRUE; +} +int ai_TryTurningTalent(object oCreature) +{ + if(!GetHasFeat(FEAT_TURN_UNDEAD, oCreature)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "1043", "Checking for Turning Targets."); + int nHDCount, nHDCount2, nRacial, nHD; + // Get characters levels. + int nClericLevel = GetLevelByClass(CLASS_TYPE_CLERIC, oCreature); + int nPaladinLevel = GetLevelByClass(CLASS_TYPE_PALADIN, oCreature); + int nBlackguardlevel = GetLevelByClass(CLASS_TYPE_BLACKGUARD, oCreature); + int nTotalLevel = GetHitDice(oCreature); + int nTurnLevel = nClericLevel; + int nClassLevel = nClericLevel; + // GZ: Since paladin levels stack when turning, blackguard levels should stack as well + // GZ: but not with the paladin levels (thus else if). + if(nBlackguardlevel - 2 > 0 && nBlackguardlevel > nPaladinLevel) + { + nClassLevel += (nBlackguardlevel - 2); + nTurnLevel += (nBlackguardlevel - 2); + } + else if(nPaladinLevel - 2 > 0) + { + nClassLevel += (nPaladinLevel - 2); + nTurnLevel += (nPaladinLevel - 2); + } + //Flags for bonus turning types + int nElemental = GetHasFeat(FEAT_AIR_DOMAIN_POWER, oCreature) + + GetHasFeat(FEAT_EARTH_DOMAIN_POWER, oCreature) + + GetHasFeat(FEAT_FIRE_DOMAIN_POWER, oCreature) + + GetHasFeat(FEAT_WATER_DOMAIN_POWER, oCreature); + int nVermin = GetHasFeat(FEAT_PLANT_DOMAIN_POWER, oCreature); + int nConstructs = GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER, oCreature); + int nGoodOrEvilDomain = GetHasFeat(FEAT_GOOD_DOMAIN_POWER, oCreature) + + GetHasFeat(FEAT_EVIL_DOMAIN_POWER, oCreature); + int nPlanar = GetHasFeat(854, oCreature); + // Get turning check average, modify if have the Sun Domain + int nChrMod = GetAbilityModifier(ABILITY_CHARISMA, oCreature); + int nTurnCheck = 15 + nChrMod; //The roll to apply to the max HD of undead that can be turned --> nTurnLevel + int nTurnHD = 12 + nChrMod + nClassLevel; //The number of HD of undead that can be turned. + if(GetHasFeat(FEAT_SUN_DOMAIN_POWER, oCreature)) + { + nTurnCheck += 2; + nTurnHD += 3; + } + //Determine the maximum HD of the undead that can be turned using a roll of 15 + ChrMod. + if(nTurnCheck == 15) nTurnLevel += 1; + else if(nTurnCheck >= 16 && nTurnCheck <= 18) nTurnLevel += 2; + else if(nTurnCheck >= 19 && nTurnCheck <= 21) nTurnLevel += 3; + else if(nTurnCheck >= 22) nTurnLevel += 4; + // Collect the number of HitDice we will affect. + int nCnt = 1; + object oEnemy = GetNearestCreature(7, 7, oCreature, nCnt); + while(oEnemy != OBJECT_INVALID && nHDCount < nTurnHD && GetDistanceBetween(oEnemy, oCreature) <= 20.0) + { + if(GetIsEnemy(oEnemy, oCreature) && !ai_Disabled(oEnemy)) + { + nRacial = GetRacialType(oEnemy); + nHD = 0; + if(nRacial == RACIAL_TYPE_UNDEAD) nHD = GetHitDice(oEnemy) + GetTurnResistanceHD(oEnemy); + else if(nRacial == RACIAL_TYPE_OUTSIDER && nGoodOrEvilDomain + nPlanar > 0) + { + //Planar turning decreases spell resistance against turning by 1/2 + if(nPlanar) nHD = GetHitDice(oEnemy) + (GetSpellResistance(oEnemy) / 2); + else nHD = GetHitDice(oEnemy) + GetSpellResistance(oEnemy); + } + else if(nRacial == RACIAL_TYPE_VERMIN && nVermin > 0) nHD = GetHitDice(oEnemy); + else if(nRacial == RACIAL_TYPE_ELEMENTAL && nElemental > 0) nHD = GetHitDice(oEnemy); + else if (nRacial == RACIAL_TYPE_CONSTRUCT && nConstructs > 0) nHD = GetHitDice(oEnemy); + // Only count undead we can defeat! + if(AI_DEBUG) ai_Debug("0i_talents", "1110", " nHD: " + IntToString(nHD) + + " nTurnLevel: " + IntToString(nTurnLevel) + + " nTurnHD: " + IntToString(nTurnHD) + + " nHDCount: " + IntToString(nHDCount)); + if(nHD > 0 && nHD <= nTurnLevel && nHD <= (nTurnHD - nHDCount)) nHDCount += nHD; + } + oEnemy = GetNearestCreature(7, 7, oCreature, ++nCnt); + } + if(AI_DEBUG) ai_Debug("0i_talents", "1089", "Found " + IntToString(nHDCount) + " hitdice to turn from my location."); + // Lets do one more check to see if we can get a better position to use TurnUndead. + nCnt = 1; + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(GetDistanceBetween(oCreature, oNearestEnemy) > AI_RANGE_MELEE) + { + oEnemy = oNearestEnemy; + if(AI_DEBUG) ai_Debug("0i_talents", "1126", GetName(oEnemy)); + while(oEnemy != OBJECT_INVALID && nHDCount2 < nTurnHD && GetDistanceBetween(oEnemy, oNearestEnemy) <= 20.0) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1129", GetName(oEnemy)); + if(GetIsEnemy(oEnemy, oCreature) && !ai_Disabled(oEnemy)) + { + nRacial = GetRacialType(oEnemy); + nHD = 0; + if(nRacial == RACIAL_TYPE_UNDEAD) nHD = GetHitDice(oEnemy) + GetTurnResistanceHD(oEnemy); + else if(nRacial == RACIAL_TYPE_OUTSIDER && nGoodOrEvilDomain + nPlanar > 0) + { + //Planar turning decreases spell resistance against turning by 1/2 + if(nPlanar) nHD = GetHitDice(oEnemy) + (GetSpellResistance(oEnemy) / 2); + else nHD = GetHitDice(oEnemy) + GetSpellResistance(oEnemy); + } + else if(nRacial == RACIAL_TYPE_VERMIN && nVermin > 0) nHD = GetHitDice(oEnemy); + else if(nRacial == RACIAL_TYPE_ELEMENTAL && nElemental > 0) nHD = GetHitDice(oEnemy); + else if (nRacial == RACIAL_TYPE_CONSTRUCT && nConstructs > 0) nHD = GetHitDice(oEnemy); + // Only count undead we can defeat! + if(AI_DEBUG) ai_Debug("0i_talents", "1140", " nHD: " + IntToString(nHD) + + " nTurnLevel: " + IntToString(nTurnLevel) + + " nTurnHD: " + IntToString(nTurnHD) + + " nHDCount2: " + IntToString(nHDCount2)); + if(nHD > 0 && nHD <= nTurnLevel && nHD <= (nTurnHD - nHDCount2)) nHDCount2 += nHD; + } + oEnemy = GetNearestCreature(7, 7, oNearestEnemy, ++nCnt); + } + } + if(AI_DEBUG) ai_Debug("0i_talents", "1148", "Found " + IntToString(nHDCount2) + " hitdice to turn from enemy location."); + if(nHDCount > nHDCount2) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1176", " My Location - nHDCount: " + IntToString(nHDCount) + + " >= nTurnHD / 2: " + IntToString(nTurnHD / 2)); + if(nHDCount < nTurnHD / 2) return FALSE; + ai_UseFeat(oCreature, FEAT_TURN_UNDEAD, oCreature); + return TRUE; + } + else + { + if(AI_DEBUG) ai_Debug("0i_talents", "1184", " Better location - nHDCount2: " + IntToString(nHDCount2) + + " >= nTurnHD / 2: " + IntToString(nTurnHD / 2)); + if(nHDCount2 < nTurnHD / 2) return FALSE; + ActionMoveToObject(oNearestEnemy, TRUE, 1.0f); + ai_UseFeat(oCreature, FEAT_TURN_UNDEAD, oCreature); + return TRUE; + } + return FALSE; +} +int ai_TryWhirlwindFeat(object oCreature) +{ + if(!GetHasFeat(FEAT_WHIRLWIND_ATTACK, oCreature)) return FALSE; + // Only worth using if there are 3+ targets. + if(AI_DEBUG) ai_Debug("0i_talents", "860", "WHIRLWIND : NumOfEnemies: " + IntToString(ai_GetNumOfEnemiesInGroup(oCreature, 3.0)) + "."); + // Shortened distance so its more effective(went from 5.0 to 2.0 and up to 3.0) + if(ai_GetNumOfEnemiesInGroup(oCreature, 3.0) < d3() + 1) return FALSE; + // * DO NOT WHIRLWIND if any of the targets are "large" or bigger + // * it seldom works against such large opponents. + // * Though its okay to use Improved Whirlwind against these targets + if((!GetHasFeat(FEAT_IMPROVED_WHIRLWIND, oCreature)) || + (GetCreatureSize(ai_GetNearestEnemy(oCreature, 1, 7, 7)) >= CREATURE_SIZE_LARGE && + GetCreatureSize(ai_GetNearestEnemy(oCreature, 2, 7, 7)) >= CREATURE_SIZE_LARGE)) + ai_UseFeat(oCreature, FEAT_WHIRLWIND_ATTACK, oCreature); + return TRUE; +} +int ai_TryWholenessOfBodyFeat(object oCreature) +{ + if(!GetHasFeat(FEAT_WHOLENESS_OF_BODY, oCreature)) return FALSE; + // Get when we are suppose to heal base off conversation with PC or + // on spawn generation. + int nHp = ai_GetPercHPLoss(oCreature); + if(nHp >= AI_HEALTH_WOUNDED) return FALSE; + ai_UseFeat(oCreature, FEAT_WHOLENESS_OF_BODY, oCreature); + return TRUE; +} +// ***************************************************************************** +// ******************** Try Physical Attack Talents **************************** +// ***************************************************************************** +// These functions try to find and use physical attack talents intelligently. + +void ai_ActionAttack(object oCreature, int nAction, object oTarget, int nInMelee = 0, int bPassive = FALSE, int nActionMode = 0) +{ + // If we are doing a ranged attack then check our position on the battlefield. + if(nAction == AI_LAST_ACTION_RANGED_ATK && ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nAction)) return; + ai_SetLastAction(oCreature, nAction); + SetLocalObject(oCreature, AI_ATTACKED_PHYSICAL, oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "894", GetName(oCreature) + " is attacking(" + IntToString(nAction) + + ") " + GetName(oTarget) + " Current Action: " + IntToString(GetCurrentAction(oCreature)) + + " Lastround Attacked Target: " + GetName(ai_GetAttackedTarget(oCreature)) + + " bPassive: " + IntToString(bPassive) + " nActionMode: " + IntToString(nActionMode)); + ActionAttack(oTarget, bPassive); + if(nActionMode == 0) ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); +} +void ai_FlyToAttacks(object oCreature, object oTarget) +{ + ai_TryWingAttacks(oCreature); + // If we don't do a Tail sweep attack then see if we can do a Tail slap! + if(!ai_TryTailSweepAttack(oCreature)) ai_TryTailSlap(oCreature); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); +} +void ai_FlyToTarget(object oCreature, object oTarget) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "908", GetName(OBJECT_SELF) + " is flying to " + GetName(oTarget) + "!"); + effect eFly = EffectDisappearAppear(GetLocation(oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, oCreature, 3.0f); + DelayCommand(4.0f, ai_FlyToAttacks(oCreature, oTarget)); + // Used to make creature wait before starting its next round. + SetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS, 5); +} +int ai_TryDragonBreathAttack(object oCreature, int nRound, object oTarget = OBJECT_INVALID) +{ + int nCnt = GetLocalInt(oCreature, "AI_DRAGONS_BREATH"); + if(AI_DEBUG) ai_Debug("0i_talents", "918", "Try Dragon Breath Attack: nRound(" + IntToString(nRound) + ")" + + " <= nCnt(" + IntToString(nCnt) + ")!"); + if(nRound <= nCnt) return FALSE; + talent tUse = GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, 20, oCreature); + if(!GetIsTalentValid(tUse)) return FALSE; + if(oTarget == OBJECT_INVALID) + { + string sIndex = IntToString(ai_GetHighestMeleeIndexNotInAOE(oCreature)); + oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + if(oTarget == OBJECT_INVALID) return FALSE; + } + SetLocalInt(oCreature, "AI_DRAGONS_BREATH", d4() + nRound); + ActionCastSpellAtObject(GetIdFromTalent(tUse), oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "1019", GetName(oCreature) + " breaths on " + GetName(oTarget) + "!"); + return TRUE; +} +void ai_DragonMeleeAttack(object oCreature, object oTarget, string sDmgDice, string sText) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "941", "oAttacker: " + GetName(oCreature) + + " oTarget: " + GetName(oTarget)); + int nDmg, nCheck, nAB = ai_GetCreatureAttackBonus(oCreature) - 5; + int nAC = GetAC(oTarget); + int nRoll = d20(); + string sHit; + // nCheck is a hit if nCheck > -1 and a miss if < 0; + if(nRoll == 20) nCheck = 20; + // We add one to the check so a equal result is still a hit. + else if(nRoll > 1) nCheck = nRoll + nAB - nAC + 1; + else nCheck == 0; + if(nCheck > 0) + { + nDmg = ai_RollDiceString(sDmgDice); + if(nCheck == 20) nDmg = nDmg * 2; + } + if(nCheck > 0) sHit = "*hit*"; + else sHit = "*miss*"; + string sMessage = ai_AddColorToText(GetName(oCreature) + "'s", AI_COLOR_LIGHT_MAGENTA) + + ai_AddColorToText(sText + "attacks " + GetName(oTarget) + " : " + sHit + " :(" + + IntToString(nRoll) + " + " + IntToString(nAB) + + " = " + IntToString(nRoll + nAB) + ")", AI_COLOR_DARK_ORANGE); + if(ai_GetIsCharacter(oTarget)) SendMessageToPC(oCreature, sMessage); + if(ai_GetIsCharacter(oTarget)) SendMessageToPC(oTarget, sMessage); + if(AI_DEBUG) ai_Debug("0i_talents", "965", "nAB: " + IntToString(nAB) + + " nAC: " + IntToString(nAC) + " nRoll: " + IntToString(nRoll) + + " nCheck: " + IntToString(nCheck) + " nDmg: " + IntToString(nDmg)); + if(nCheck <= 0) return; + // Apply any damage to the target! + effect eDmg = EffectDamage(nDmg, DAMAGE_TYPE_BLUDGEONING); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); +} +// Checks to see if a dragon can use its wings on a nearby enemy. +// Checks the right side and then the left side to see if it can attack. +int ai_TryWingAttacks(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "977", GetName(oCreature) + " is checking for wing Attacks!"); + // Only Medium size dragons can use thier wings in combat. + // We use HitDice to base size S:1-5, M:6-11, L:12-17, H:18-29, G:30-39, C:40+. + int nHitDice = GetHitDice(oCreature); + if(nHitDice <= 5) return FALSE; + int nDragonSize; + string sDmgDice, sMessage; + float fSize; + // Get the stats based on the size of the dragon. + if(nHitDice < 12) { fSize = 5.0f; nDragonSize = 3; sDmgDice = "1d4"; } // Medium + else if(nHitDice < 18) { fSize = 10.0f; nDragonSize = 4; sDmgDice = "1d6"; } // Large + else if(nHitDice < 30) { fSize = 10.0f; nDragonSize = 5; sDmgDice = "1d8"; } // Huge + else if(nHitDice < 40) { fSize = 15.0f; nDragonSize = 6; sDmgDice = "2d6"; } // Gargantuan + else { fSize = 15.0f; nDragonSize = 7; sDmgDice = "2d8"; } // Colossal + // Add half the dragons strength modifier. + int nDmg = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(nDmg > 0) sDmgDice = sDmgDice + "+" + IntToString(nDmg / 2); + if(AI_DEBUG) ai_Debug("0i_talents", "994", "nHitDice: " + IntToString(nHitDice) + + " nDragonSize: " + IntToString(nDragonSize) + + " sDmgDice: " + sDmgDice + " nDmg: " + IntToString(nDmg)); + // Get the closest enemy to our right wing. + location lWing = GetFlankingRightLocation(oCreature); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fSize, lWing); + while(oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1002", "oTarget: " + GetName(oTarget)); + if(GetIsEnemy(oTarget, oCreature) && !GetIsDead(oTarget)) break; + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fSize, lWing); + } + if(oTarget != OBJECT_INVALID) ai_DragonMeleeAttack(oCreature, oTarget, sDmgDice, " right wing "); + // Get the closest enemy to our left wing. + lWing = GetFlankingLeftLocation(oCreature); + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fSize, lWing); + while(oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1012", "oTarget: " + GetName(oTarget)); + if(GetIsEnemy(oTarget, oCreature) && !GetIsDead(oTarget)) break; + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fSize, lWing); + } + if(oTarget != OBJECT_INVALID) ai_DragonMeleeAttack(oCreature, oTarget, sDmgDice, " left wing "); + return TRUE; +} +// Looks behind the dragon to see if it can use it's tail slap on an enemy. +int ai_TryTailSlap(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1022", GetName(OBJECT_SELF) + " is checking for tail slap Attack!"); + // Only Large size dragons can use thier tail in combat. + // We use HitDice to base size S:1-5, M:6-11, L:12-17, H:18-29, G:30-39, C:40+. + int nHitDice = GetHitDice(oCreature); + if(nHitDice <= 11) return FALSE; + int nDragonSize; + string sDmgDice, sMessage; + float fSize; + // Get the stats based on the size of the dragon. + if(nHitDice < 12) { fSize = 5.0f; nDragonSize = 3; sDmgDice = "1d4"; } // Medium + else if(nHitDice < 18) { fSize = 10.0f; nDragonSize = 4; sDmgDice = "1d6"; } // Large + else if(nHitDice < 30) { fSize = 10.0f; nDragonSize = 5; sDmgDice = "1d8"; } // Huge + else if(nHitDice < 40) { fSize = 15.0f; nDragonSize = 6; sDmgDice = "2d6"; } // Gargantuan + else { fSize = 15.0f; nDragonSize = 7; sDmgDice = "2d8"; } // Colossal + // Add one and a half the dragons strength modifier. + int nDmg = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(nDmg > 0) sDmgDice = sDmgDice + "+" + IntToString(nDmg + nDmg / 2); + if(AI_DEBUG) ai_Debug("0i_talents", "1039", "nHitDice: " + IntToString(nHitDice) + + " nDragonSize: " + IntToString(nDragonSize) + + " sDmgDice: " + sDmgDice + " nDmg: " + IntToString(nDmg)); + // Get the closest enemy to our tail. + location lTail = GetBehindLocation(oCreature); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fSize, lTail); + while(oTarget != OBJECT_INVALID) + { + if(GetIsEnemy(oTarget, oCreature) && !GetIsDead(oTarget)) break; + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fSize, lTail); + } + if(oTarget != OBJECT_INVALID) ai_DragonMeleeAttack(oCreature, oTarget, sDmgDice, " tail ");\ + return TRUE; +} +void ai_CrushEffect(object oCreature, object oBaseTarget, int nHitDice) +{ + int nDragonSize, nAtkValue, nDC = ai_GetDragonDC(oCreature); + string sDmgDice, sMessage; + location lImpact = GetLocation(oBaseTarget); + float fSize; + // Get the stats based on the size of the dragon. + if(nHitDice < 30) { fSize = 15.0f; nDragonSize = 5; sDmgDice = "2d8"; } // Huge + else if(nHitDice < 40) { fSize = 25.0f; nDragonSize = 6; sDmgDice = "4d6"; } // Gargantuan + else { fSize = 45.0f; nDragonSize = 7; sDmgDice = "4d8"; } // Colossal + // Add the dragons strength modifier 1.5 times. + int nDmgBonus = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(nDmgBonus > 0) sDmgDice = sDmgDice + "+" + IntToString(nDmgBonus + nDmgBonus / 2); + // Dragon flies up and then crushes the area below it. + effect eDmg, eKnockDown = EffectKnockdown(); + effect eImpact = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fSize, lImpact); + while(oTarget != OBJECT_INVALID) + { + if(ai_GetIsCharacter(oTarget)) DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oTarget)); + // If they have evasion they automatically dodge the crush attack. + if(!GetHasFeat(FEAT_EVASION, oTarget) && oTarget != oCreature) + { + if(!ReflexSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oCreature)) + { + eDmg =EffectDamage(ai_RollDiceString(sDmgDice), DAMAGE_TYPE_BLUDGEONING); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); + sMessage = ai_AddColorToText(GetName(oCreature), AI_COLOR_LIGHT_MAGENTA) + + ai_AddColorToText(" crushes " + GetName(oTarget) + ".", AI_COLOR_DARK_ORANGE); + if(ai_GetIsCharacter(oTarget)) SendMessageToPC(oTarget, sMessage); + // Must be 3 sizes smaller to be affected by extra damage and knockdown. + if(nDragonSize - 2 < GetCreatureSize(oTarget)) + { + if(!GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN)) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockDown, oTarget, 6.0f); + } + } + } + } + else + { + if(ai_GetIsCharacter(oTarget)) + { + sMessage = ai_AddColorToText(GetName(oTarget), AI_COLOR_LIGHT_MAGENTA) + + ai_AddColorToText(" dodges the crush attack from " + GetName(oTarget) + ".", AI_COLOR_DARK_ORANGE); + if(ai_GetIsCharacter(oTarget)) SendMessageToPC(oTarget, sMessage); + } + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fSize, lImpact); + } + // Now do normal attacks! + ai_FlyToAttacks(oCreature, oBaseTarget); +} +int ai_TryCrushAttack(object oCreature, object oTarget) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1110", GetName(OBJECT_SELF) + " is checking for crush Attack!"); + // Only Huge size dragons can use crush attack. + // We use HitDice to base size S:1-5, M:6-11, L:12-17, H:18-29, G:30-39, C:40+. + int nHitDice = GetHitDice(oCreature); + if(nHitDice <= 17) return FALSE; + int nCrush = GetLocalInt(oCreature, "0_DRAGON_CRUSH") - 1; + if(nCrush > 0) + { + SetLocalInt(oCreature, "0_DRAGON_CRUSH", nCrush); + return FALSE; + } + effect eFly = EffectDisappearAppear(GetLocation(oTarget)); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, oCreature, 3.0f); + DelayCommand(4.0f, ai_CrushEffect(oCreature, oTarget, nHitDice)); + // Used to make creature wait before starting its next round. + SetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS, 5); + // We only crush every 3 rounds if we can. + SetLocalInt(oCreature, "0_DRAGON_CRUSH", 3); + return TRUE; +} +int ai_TryTailSweepAttack(object oCreature) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1132", GetName(oCreature) + " is checking for tail sweep Attack!"); + // Only Gargantuan size dragons can use tail sweep attack. + // We use HitDice to base size S:1-5, M:6-11, L:12-17, H:18-29, G:30-40, C:40+. + int nHitDice = GetHitDice(oCreature); + if(nHitDice <= 29) return FALSE; + int nSweep = GetLocalInt(oCreature, "0_DRAGON_SWEEP") - 1; + if(nSweep > 0) + { + SetLocalInt(oCreature, "0_DRAGON_SWEEP", nSweep); + return FALSE; + } + int nDragonSize, nAtkValue, nDC = ai_GetDragonDC(oCreature); + string sDmgDice, sMessage; + float fSize; + // Get the stats based on the size of the dragon. + if(nHitDice < 33) { fSize = 15.0f; nDragonSize = 6; sDmgDice = "2d6"; } // Gargantuan + else { fSize = 40.0f; nDragonSize = 7; sDmgDice = "2d8"; } // Colossal + location lImpact = GetBehindLocation(oCreature); + // We always sweep if we have the opportunity. + // Add the dragons strength modifier 1.5 times. + int nDmgBonus = GetAbilityModifier(ABILITY_STRENGTH, oCreature); + if(nDmgBonus > 0) sDmgDice = sDmgDice + "+" + IntToString(nDmgBonus + nDmgBonus / 2); + // Sweeps any creatures behind them. + effect eDmg; + effect eKnockDown = EffectKnockdown(); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fSize, lImpact); + while(oTarget != OBJECT_INVALID) + { + sMessage = ai_AddColorToText(GetName(oCreature), AI_COLOR_LIGHT_MAGENTA) + + ai_AddColorToText(" sweeps " + GetName(oTarget) + ".", AI_COLOR_ORANGE); + if(ai_GetIsCharacter(oTarget)) SendMessageToPC(oTarget, sMessage); + // If they have evasion they automatically dodge the sweep attack. + if(!GetHasFeat(FEAT_EVASION, oTarget) && oTarget != oCreature) + { + if(!ReflexSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oCreature)) + { + eDmg = EffectDamage(ai_RollDiceString(sDmgDice), DAMAGE_TYPE_BLUDGEONING); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); + // Must be 4 sizes smaller to be affected by extra damage and knockdown. + if(nDragonSize - 3 < GetCreatureSize(oTarget)) + { + if(!GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN)) + { + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockDown, oTarget, 12.0f); + } + } + } + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, fSize, lImpact); + } + // We only sweep every 3 rounds if we can. + SetLocalInt(oCreature, "0_DRAGON_SWEEP", 3); + return TRUE; +} +int ai_TrySneakAttack(object oCreature, int nInMelee, int bAlwaysAtk = TRUE) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1188", GetName(OBJECT_SELF) + " is checking for melee Sneak Attack!"); + if(!GetHasFeat(FEAT_SNEAK_ATTACK, oCreature)) return FALSE; + // Lets get the nearest target that is attacking someone besides me. + object oTarget = OBJECT_INVALID; + oTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + string sIndex; + // Check if we have Mobility, Spring Attack or a good tumble. + // if we do then look for other targets besides who we are in melee with. + if(!nInMelee) sIndex = IntToString(ai_GetBestSneakAttackIndex(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk)); + // If there are few enemies then we can safely move around. + else if(nInMelee < 3 || ai_CanIMoveInCombat(oCreature)) + { + sIndex = IntToString(ai_GetBestSneakAttackIndex(oCreature, AI_RANGE_MELEE)); + } + // Ok we are in a serious fight so lets not give attack of opportunities. + else sIndex = IntToString(ai_GetNearestIndex(oCreature, AI_RANGE_MELEE)); + oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + } + if(oTarget == OBJECT_INVALID) return FALSE; + int nRacialType = GetRacialType(oTarget); + if(nRacialType == RACIAL_TYPE_CONSTRUCT || nRacialType == RACIAL_TYPE_UNDEAD) return FALSE; + if(ai_GetHasEffectType(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) return FALSE; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return TRUE; +} +int ai_TryRangedSneakAttack(object oCreature, int nInMelee) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1209", GetName(oCreature) + " is checking for a Ranged Sneak Attack!"); + // If we have Sneak Attack then we should be attacking targets that + // are busy fighting so we can get extra damage. + if(!GetHasFeat(FEAT_SNEAK_ATTACK, oCreature)) return FALSE; + object oTarget = OBJECT_INVALID; + oTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = GetLocalObject(oCreature, AI_ENEMY + IntToString(ai_GetBestSneakAttackIndex(oCreature))); + if(oTarget == OBJECT_INVALID) return FALSE; + int nRacialType = GetRacialType(oTarget); + if(nRacialType == RACIAL_TYPE_CONSTRUCT || nRacialType == RACIAL_TYPE_UNDEAD) return FALSE; + if(ai_GetHasEffectType(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) return FALSE; + // If we have a target and are not within 30' then move within 30'. + if(GetDistanceToObject(oTarget) > AI_RANGE_CLOSE) ActionMoveToObject(oTarget, TRUE, AI_RANGE_CLOSE); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return TRUE; +} +int ai_TryMeleeTalents(object oCreature, object oTarget) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1224", "Check category melee talents!"); + talent tUse = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_MELEE, 20, oCreature); + if(!GetIsTalentValid(tUse)) return FALSE; + int nId = GetIdFromTalent(tUse); + if(AI_DEBUG) ai_Debug("0i_talents", "1228", "TALENT_CATEGORY_MELEE_TALENTS nId: " + IntToString(nId)); + if(nId == FEAT_POWER_ATTACK) { if(ai_TryPowerAttackFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_EXPERTISE) { if(ai_TryExpertiseFeat(oCreature)) return TRUE; } + else if(nId == FEAT_KNOCKDOWN) { if(ai_TryKnockdownFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_SMITE_EVIL) { if(ai_TrySmiteEvilFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_SMITE_GOOD) { if(ai_TrySmiteGoodFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_IMPROVED_POWER_ATTACK) { if(ai_TryImprovedPowerAttackFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_IMPROVED_EXPERTISE) { if(ai_TryImprovedExpertiseFeat(oCreature)) return TRUE; } + else if(nId == FEAT_FLURRY_OF_BLOWS) { if(ai_TryFlurryOfBlowsFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_STUNNING_FIST) { if(ai_TryStunningFistFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_SAP) { if(ai_TrySapFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_DISARM) { if(ai_TryDisarmFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_KI_DAMAGE) { if(ai_TryKiDamageFeat(oCreature, oTarget)) return TRUE; } + else if(nId == FEAT_CALLED_SHOT) { if(ai_TryCalledShotFeat(oCreature, oTarget)) return TRUE; } + return FALSE; +} +// ***************************************************************************** +// ***************************** TALENT SCRIPTS ****************************** +// ***************************************************************************** +// These functions do not fall into another section. + +int ai_GetMonsterTalentMaxLevel(object oCreature) +{ + // Monsters should use either the best spell they have or a random spell so + // they all don't look robotic. Mix it up based on an Intelligence check. + int nMaxLevel = (ai_GetCharacterLevels(oCreature) + 1) / 2; + if(nMaxLevel > 9) nMaxLevel = 9; + if(AI_DEBUG) ai_Debug("0i_talents", "1258", "nMaxLevel: " + IntToString(nMaxLevel)); + return nMaxLevel; +} +int ai_GetAssociateTalentMaxLevel(object oCreature, int nDifficulty) +{ + int nLevel = (ai_GetCharacterLevels(oCreature) + 1) / 2; + if(nLevel > 20) nLevel = 20; + int nMaxLevel = (nLevel * nDifficulty) / 20; + if(nMaxLevel < 1) nMaxLevel = 1; + if(AI_DEBUG) ai_Debug("0i_talents", "1267", "nLevel: " + IntToString(nLevel) + + " nMaxLevel: " + IntToString(nMaxLevel)); + return nMaxLevel; +} +int ai_GetHasTalent(object oCreature, int nTalent) +{ + string sCategory = Get2DAString("ai_spells", "Category", nTalent); + json jCategory = GetLocalJson(oCreature, sCategory); + if(JsonGetType(jCategory) == JSON_TYPE_NULL) return FALSE; + int nLevel, nSlot, nSlotIndex, nMaxSlotIndex, nSpell; + json jLevel, jTalent; + // Loop through nLevels looking for nTalent + while(nLevel <= 9) + { + // Get the array of nLevel. + jLevel = JsonArrayGet(jCategory, nLevel); + nMaxSlotIndex = JsonGetLength(jLevel); + if(nMaxSlotIndex > 0) + { + // Get the talent within nLevel cycling from the first to the last. + nSlotIndex = 0; + while (nSlotIndex < nMaxSlotIndex) + { + jTalent= JsonArrayGet(jLevel, nSlotIndex); + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + if(nSpell == nTalent) return TRUE; + nSlotIndex++; + } + } + nLevel++; + } + return FALSE; +} +object ai_CheckTalentForBuffing(object oCreature, string sCategory, int nSpell) +{ + // Should we buff this monster caster? Added legacy code just in case. + if((sCategory == "P" || sCategory == "E" || sCategory == "S") && + (GetLocalInt(GetModule(), AI_RULE_BUFF_MONSTERS) || + GetLocalInt(oCreature, "NW_GENERIC_MASTER") & 0x04000000)) return ai_GetBuffTarget(oCreature, nSpell); + //if(sCategory == "S" && GetLocalInt(GetModule(), AI_RULE_PRESUMMON)) return oCreature; + return OBJECT_INVALID; +} +int ai_UseBuffTalent(object oCreature, int nClass, int nLevel, int nSlot, int nSpell, int nType, object oTarget, object oItem) +{ + if(nType == AI_TALENT_TYPE_SPELL) + { + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot)) + { + ai_CastMemorizedSpell(oCreature, nClass, nLevel, nSlot, oTarget, TRUE); + return TRUE; + } + } + else if(GetSpellUsesLeft(oCreature, nClass, nSpell)) + { + ai_CastKnownSpell(oCreature, nClass, nSpell, oTarget, TRUE); + return TRUE; + } + } + else if(nType == AI_TALENT_TYPE_SP_ABILITY) + { + ActionCastSpellAtObject(nSpell, oTarget, 255, FALSE, 0, 0, TRUE, 255); + } + /* This will not work as there is no cheat option for using an item. + else if(nType == AI_TALENT_TYPE_ITEM) + { + int nBaseItem = GetBaseItemType(oItem); + if(!AI_BUFF_MONSTER_POTIONS && + (nBaseItem == BASE_ITEM_POTIONS || nBaseItem == BASE_ITEM_ENCHANTED_POTION)) return FALSE; + itemproperty ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + if(nIndex++ == nSlot) break; + ipProp = GetNextItemProperty(oItem); + } + // Cast items have the following: + // 1)Single_Use. + // 2-6) Charges/Use [Note: 7 is 0 charges per use]. + // 8-12) Uses/Day [Note: 13 is unlimited uses per day]. + // We set the slot to -1 to let the other function know we need this talent removed. + int nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses == 1) jTalent = JsonArrayInsert(jTalent, JsonInt(-1), 4); + else if(nUses > 1 && nUses < 7) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1319", "Item charges: " + IntToString(GetItemCharges(oItem))); + int nCharges = GetItemCharges(oItem); + if(nUses == 6 && nCharges == 1 || nUses == 5 && nCharges < 4 || + nUses == 4 && nCharges < 6 || nUses == 3 && nCharges < 8 || + nUses == 2 && nCharges < 10) return FALSE; + } + else if(nUses > 7 && nUses < 13) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1327", "Item uses: " + IntToString(GetItemPropertyUsesPerDayRemaining(oItem, ipProp))); + int nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(nUses == 8 && nPerDay == 1 || nUses == 9 && nPerDay < 4 || + nUses == 10 && nPerDay < 6 || nUses == 11 && nPerDay < 8 || + nUses == 12 && nPerDay < 10) return FASLE; + } + ActionUseItemOnObject(oItem, ipProp, oTarget, nSubIndex); + return TRUE; + } */ + return FALSE; +} +int ai_SpellRestricted(int nSpell) +{ + json jRSpells = GetLocalJson(GetModule(), AI_RULE_RESTRICTED_SPELLS); + int nIndex, nMaxIndex = JsonGetLength(jRSpells); + while(nIndex < nMaxIndex) + { + if(JsonGetInt(JsonArrayGet(jRSpells, nIndex)) == nSpell) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1703", IntToString(nSpell) + " is has been restricted and will be ignored!"); + return TRUE; + } + nIndex++; + } + return FALSE; +} +void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bMonster, object oItem = OBJECT_INVALID) +{ + // Players/Admins can restrict some spells. + if(ai_SpellRestricted(nSpell)) return; + // Get the talent category, we organize all talents by categories. + string sCategory = Get2DAString("ai_spells", "Category", nSpell); + // If it is a blank talent or it is an Area of Effect talent we skip. + if(sCategory == "" || sCategory == "A") return; + // Check to see if we should be prebuffing. + if(bMonster) + { + int nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell)); + if(nSpellBuffDuration == 3) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1600", GetName(oCreature) + " is buffing with spell " + IntToString(nSpell)); + object oTarget = ai_CheckTalentForBuffing(oCreature, sCategory, nSpell); + if(oTarget != OBJECT_INVALID && + ai_UseBuffTalent(oCreature, nClass, nLevel, nSlot, nSpell, nType, oTarget, oItem)) return; + } + } + json jCategory = GetLocalJson(oCreature, sCategory); + // With no jCategory then we make one with all 0-9 levels. + if(JsonGetType(jCategory) == JSON_TYPE_NULL) + { + jCategory = JsonArray(); + jCategory = JsonArrayInsert(jCategory, JsonArray(), 0); + int nNewLevel = 9; + while(nNewLevel > 0) + { + jCategory = JsonArrayInsert(jCategory, JsonArray()); + nNewLevel--; + } + } + // Get the current Level so we can save to it. + json jLevel = JsonArrayGet(jCategory, nJsonLevel); + json jTalent = JsonArray(); + if(nType == AI_TALENT_TYPE_SPELL || nType == AI_TALENT_TYPE_SP_ABILITY) + { + jTalent = JsonArrayInsert(jTalent, JsonInt(nType), 0); + jTalent = JsonArrayInsert(jTalent, JsonInt(nSpell)); + jTalent = JsonArrayInsert(jTalent, JsonInt(nClass)); + jTalent = JsonArrayInsert(jTalent, JsonInt(nLevel)); + jTalent = JsonArrayInsert(jTalent, JsonInt(nSlot)); + } + else if(nType == AI_TALENT_TYPE_ITEM) + { + jTalent = JsonArrayInsert(jTalent, JsonInt(nType), 0); + jTalent = JsonArrayInsert(jTalent, JsonInt(nSpell)); + jTalent = JsonArrayInsert(jTalent, JsonString(ObjectToString(oItem))); + jTalent = JsonArrayInsert(jTalent, JsonInt(nLevel)); + jTalent = JsonArrayInsert(jTalent, JsonInt(nSlot)); + } + jLevel = JsonArrayInsert(jLevel, jTalent); + jCategory = JsonArraySet(jCategory, nJsonLevel, jLevel); + SetLocalJson(oCreature, sCategory, jCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "1777", sCategory + ": " + JsonDump(jCategory, 1)); + if(AI_DEBUG) ai_Debug("0i_talents", "1778", "AI_MAX_TALENT: " + + IntToString(GetLocalInt(oCreature, AI_MAX_TALENT + sCategory)) + + " nJsonLevel: " + IntToString(nJsonLevel)); + // Set AI_MAX_TALENT if this talent is higher than the maximum. + if(nJsonLevel > GetLocalInt(oCreature, AI_MAX_TALENT + sCategory)) + { + SetLocalInt(oCreature, AI_MAX_TALENT + sCategory, nJsonLevel); + } +} +// For removing used up spell slots. +void ai_RemoveTalent(object oCreature, json jCategory, json jLevel, string sCategory, int nLevel, int nSlotIndex) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1400", "removing Talent from slot: " + IntToString(nSlotIndex)); + jLevel = JsonArrayDel(jLevel, nSlotIndex); + if(AI_DEBUG) ai_Debug("0i_talents", "1402", "jLevel: " + JsonDump(jLevel, 2)); + jCategory = JsonArraySet(jCategory, nLevel, jLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "1404", "jCategory: " + JsonDump(jCategory, 2)); + SetLocalJson(oCreature, sCategory, jCategory); +} +// For removing Sorcerer/Bard spell levels once used up. +void ai_RemoveTalentLevel(object oCreature, json jCategory, json jLevel, string sCategory, int nLevel) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1410", "removing Talent level: " + IntToString(nLevel)); + jCategory = JsonArrayDel(jCategory, nLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "1412", "jCategory: " + JsonDump(jCategory, 2)); + SetLocalJson(oCreature, sCategory, jCategory); +} +void ai_SetCreatureSpellTalents(object oCreature, int bMonster) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1417", GetName(oCreature) + ": Setting Spell Talents for combat [Buff: " + + IntToString(bMonster) + "]."); + // Cycle through all classes and spells. + int nClassPosition = 1, nMaxSlot, nLevel, nSlot, nSpell, nIndex, nMetaMagic; + int nClass = GetClassByPosition(nClassPosition, oCreature); + while(nClassPosition <= AI_MAX_CLASSES_PER_CHARACTER && nClass != CLASS_TYPE_INVALID) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1824", "nClass: " + IntToString(nClass) + + " nClassPosition: " + IntToString(nClassPosition) + + " SpellCaster: " + Get2DAString("classes", "SpellCaster", nClass) + + " Memorized: " + Get2DAString("classes", "MemorizesSpells", nClass)); + if(Get2DAString("classes", "SpellCaster", nClass) == "1") + { + // Search all memorized spells for the spell. + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + // Check each level organizing from highest to lowest. + nLevel = (GetLevelByPosition(nClassPosition, oCreature) + 1) / 2; + if(nLevel > 9) nLevel = 9; + while(nLevel > -1) + { + // Check each slot within each level. + nMaxSlot = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "1434", "nClass: " + IntToString(nClass) + + " nLevel: " + IntToString(nLevel) + " nMaxSlot: " + + IntToString(nMaxSlot)); + nSlot = 0; + while(nSlot < nMaxSlot) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1440", "nSlot: " + IntToString(nSlot) + " nSpell: " + + IntToString(GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot)) + " spell memorized: " + + IntToString(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot))); + if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot) == 1) + { + nSpell = GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot); + /* Spells are already at the higher level when saved as a talent. + // Move a spell up to a different JsonLevel as higher Jsonlevel + // spells usually get cast first. + nMetaMagic = GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot); + if(nMetaMagic > 0) + { + if(nMetaMagic == METAMAGIC_STILL) nMetaMagic = 1; + else if(nMetaMagic == METAMAGIC_EXTEND) nMetaMagic = 1; + else if(nMetaMagic == METAMAGIC_SILENT) nMetaMagic = 1; + else if(nMetaMagic == METAMAGIC_EMPOWER) nMetaMagic = 2; + else if(nMetaMagic == METAMAGIC_MAXIMIZE) nMetaMagic = 3; + else if(nMetaMagic == METAMAGIC_QUICKEN) nMetaMagic = 4; + nAdjLevel = nLevel + nMetaMagic; + if(nAdjLevel > 9) nAdjLevel = 9; + } + else nAdjLevel = nLevel; */ + ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster); + } + nSlot++; + } + nLevel--; + } + } + // Check non-memorized known lists for the spell. + else + { + // Check each level starting with the highest to lowest. + nLevel = (GetLevelByPosition(nClassPosition, oCreature) + 1) / 2; + if(nLevel > 9) nLevel = 9; + while(nLevel > -1) + { + // Check each slot within each level. + nMaxSlot = GetKnownSpellCount(oCreature, nClass, nLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "1462", "nClass: " + IntToString(nClass) + + " nLevel: " + IntToString(nLevel) + " nMaxSlot: " + + IntToString(nMaxSlot)); + nSlot = 0; + while(nSlot < nMaxSlot) + { + nSpell = GetKnownSpellId(oCreature, nClass, nLevel, nSlot); + if(AI_DEBUG) ai_Debug("0i_talents", "1469", "nSlot: " + IntToString(nSlot) + + " nSpell: " + IntToString(nSpell) + " nUsesLeft: " + + IntToString(GetSpellUsesLeft(oCreature, nClass, nSpell))); + if(GetSpellUsesLeft(oCreature, nClass, nSpell) > 0) + { + ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster); + } + nSlot++; + } + nLevel--; + } + } + } + nClassPosition++; + nClass = GetClassByPosition(nClassPosition, oCreature); + } +} +void ai_SetCreatureSpecialAbilityTalents(object oCreature, int bMonster) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1488", GetName(oCreature) + ": Setting Special Ability Talents for combat."); + // Cycle through all the creatures special abilities. + int nMaxSpecialAbilities = GetSpellAbilityCount(oCreature); + if(AI_DEBUG) ai_Debug("0i_talents", "1491", IntToString(GetSpellAbilityCount(oCreature)) + " Spell abilities."); + if(nMaxSpecialAbilities) + { + int nIndex, nSpell, nLevel; + while(nIndex < nMaxSpecialAbilities) + { + nSpell = GetSpellAbilitySpell(oCreature, nIndex); + if(GetSpellAbilityReady(oCreature, nSpell)) + { + nLevel = StringToInt(Get2DAString("spells", "Innate", nSpell)); + ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_SP_ABILITY, bMonster); + } + nIndex++; + } + } +} +void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bEquiped = FALSE) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1509", "Checking Item properties on " + GetName(oItem)); + // We have established that we can use the item if it is equiped. + if(!bEquiped && !ai_CheckIfCanUseItem(oCreature, oItem)) return; + // Get or create an Immunity in json so we can check item immunities quickly. + int nSpellImmunity, bHasItemImmunity, nPerDay, nCharges, nUses, bSaveTalent; + json jImmunity = GetLocalJson(oCreature, AI_TALENT_IMMUNITY); + if(JsonGetType(jImmunity) == JSON_TYPE_NULL) jImmunity = JsonArray(); + int nIprpSubType, nSpell, nLevel, nIPType, nIndex; + itemproperty ipProp = GetFirstItemProperty(oItem); + // Lets skip this if there are no properties. + if(!GetIsItemPropertyValid(ipProp)) return; + // Check for cast spell property and add them to the talent list. + while(GetIsItemPropertyValid(ipProp)) + { + nIPType = GetItemPropertyType(ipProp); + if(AI_DEBUG) ai_Debug("0i_talents", "1895", "ItempropertyType(15/80/53): " + IntToString(nIPType)); + if(nIPType == ITEM_PROPERTY_CAST_SPELL) + { + bSaveTalent = TRUE; + // Get how they use the item (charges or uses per day). + nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses > 1 && nUses < 7) + { + nCharges = GetItemCharges(oItem); + if(AI_DEBUG) ai_Debug("0i_talents", "1530", "Charges per use: " + IntToString(nUses) + + " Item charges: " + IntToString(nCharges)); + if((nUses == IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE && nCharges < 1) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE && nCharges < 2) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_3_CHARGES_PER_USE && nCharges < 3) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_4_CHARGES_PER_USE && nCharges < 4) || + (nUses == IP_CONST_CASTSPELL_NUMUSES_5_CHARGES_PER_USE && nCharges < 5)) bSaveTalent = FALSE; + } + else if(nUses > 7 && nUses < 13) + { + nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(AI_DEBUG) ai_Debug("0i_talents", "1676", "Item uses: " + IntToString(nPerDay)); + if(nPerDay == 0) bSaveTalent = FALSE; + } + if(bSaveTalent) + { + // SubType is the ip spell index for iprp_spells.2da + nIprpSubType = GetItemPropertySubType(ipProp); + nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType)); + nLevel = StringToInt(Get2DAString("iprp_spells", "InnateLvl", nIprpSubType)); + ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, oItem); + } + } + else if(nIPType == ITEM_PROPERTY_HEALERS_KIT) + { + // Lets set Healing kits as Cure Light Wounds since they heal 1d20 in combat. + nSpell = SPELL_CURE_MINOR_WOUNDS; + // Save the healer kit as level 9 so we can use them first. + // Must also have ranks in healing kits. + if(GetSkillRank(SKILL_HEAL, oCreature) > 0) + { + ai_SaveTalent(oCreature, 255, 7, 0, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, oItem); + } + } + if(bEquiped) + { + if(nIPType == ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL) + { + bHasItemImmunity = TRUE; + nSpellImmunity = GetItemPropertyCostTableValue(ipProp); + nSpellImmunity = StringToInt(Get2DAString("iprp_spellcost", "SpellIndex", nSpellImmunity)); + //if(AI_DEBUG) ai_Debug("0i_talents", "1950", "SpellImmunity to " + Get2DAString("spells", "Label", nSpellImmunity)); + jImmunity = JsonArrayInsert(jImmunity, JsonInt(nSpellImmunity)); + } + else if(nIPType == ITEM_PROPERTY_HASTE) + { + SetLocalInt(oCreature, sIPHasHasteVarname, TRUE); + } + else if(nIPType == ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE) + { + int nBit, nIpSubType = GetItemPropertySubType(ipProp); + if(AI_DEBUG) ai_Debug("0i_talents", "1957", "nIPSubType: " + IntToString(nIpSubType)); + if(nIpSubType == 0) nBit = DAMAGE_TYPE_BLUDGEONING; + else if(nIpSubType == 1) nBit = DAMAGE_TYPE_PIERCING; + else if(nIpSubType == 2) nBit = DAMAGE_TYPE_SLASHING; + else if(nIpSubType == 5) nBit = DAMAGE_TYPE_MAGICAL; + else if(nIpSubType == 6) nBit = DAMAGE_TYPE_ACID; + else if(nIpSubType == 7) nBit = DAMAGE_TYPE_COLD; + else if(nIpSubType == 8) nBit = DAMAGE_TYPE_DIVINE; + else if(nIpSubType == 9) nBit = DAMAGE_TYPE_ELECTRICAL; + else if(nIpSubType == 10) nBit = DAMAGE_TYPE_FIRE; + else if(nIpSubType == 11) nBit = DAMAGE_TYPE_NEGATIVE; + else if(nIpSubType == 12) nBit = DAMAGE_TYPE_POSITIVE; + else if(nIpSubType == 13) nBit = DAMAGE_TYPE_SONIC; + if(nBit > 0) ai_SetItemProperty(oCreature, sIPImmuneVarname, nBit, TRUE); + } + else if(nIPType == ITEM_PROPERTY_DAMAGE_RESISTANCE) + { + int nBit, nIpSubType = GetItemPropertySubType(ipProp); + if(nIpSubType == 0) nBit = DAMAGE_TYPE_BLUDGEONING; + else if(nIpSubType == 1) nBit = DAMAGE_TYPE_PIERCING; + else if(nIpSubType == 2) nBit = DAMAGE_TYPE_SLASHING; + else if(nIpSubType == 5) nBit = DAMAGE_TYPE_MAGICAL; + else if(nIpSubType == 6) nBit = DAMAGE_TYPE_ACID; + else if(nIpSubType == 7) nBit = DAMAGE_TYPE_COLD; + else if(nIpSubType == 8) nBit = DAMAGE_TYPE_DIVINE; + else if(nIpSubType == 9) nBit = DAMAGE_TYPE_ELECTRICAL; + else if(nIpSubType == 10) nBit = DAMAGE_TYPE_FIRE; + else if(nIpSubType == 11) nBit = DAMAGE_TYPE_NEGATIVE; + else if(nIpSubType == 12) nBit = DAMAGE_TYPE_POSITIVE; + else if(nIpSubType == 13) nBit = DAMAGE_TYPE_SONIC; + if(nBit > 0) ai_SetItemProperty(oCreature, sIPResistVarname, nBit, TRUE); + } + else if(nIPType == ITEM_PROPERTY_DAMAGE_REDUCTION) + { + int nIpSubType = GetItemPropertySubType(ipProp); + SetLocalInt(oCreature, sIPReducedVarname, nIpSubType); + } + } + nIndex++; + ipProp = GetNextItemProperty(oItem); + } + // If nSpellImmunity has been set then we need to save our Immunity json. + if(bHasItemImmunity) SetLocalJson(oCreature, AI_TALENT_IMMUNITY, jImmunity); +} +void ai_SetCreatureItemTalents(object oCreature, int bMonster) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1561", GetName(oCreature) + ": Setting Item Talents for combat."); + int bEquiped; + string sSlots; + // Cycle through all the creatures inventory items. + object oItem = GetFirstItemInInventory(oCreature); + while(oItem != OBJECT_INVALID) + { + if(GetIdentified(oItem)) + { + // Does the item need to be equiped to use its powers? + sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)); + if(AI_DEBUG) ai_Debug("0i_talents", "1572", GetName(oItem) + " requires " + Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) + " slots."); + if(sSlots == "0x00000") ai_CheckItemProperties(oCreature, oItem, bMonster); + } + oItem = GetNextItemInInventory(oCreature); + } + int nSlot; + // Cycle through all the creatures equiped items. + oItem = GetItemInSlot(nSlot, oCreature); + while(nSlot < 11) + { + if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, TRUE); + oItem = GetItemInSlot(++nSlot, oCreature); + } + oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature); + if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, TRUE); +} +void ai_SetCreatureTalents(object oCreature, int bMonster) +{ + json jCreature = ObjectToJson(oCreature); + //if(AI_DEBUG) ai_Debug("0i_talents", "2072", GetName(oCreature) + " jCreature: " + JsonDump(jCreature, 4)); + if(GetLocalInt(oCreature, AI_TALENTS_SET)) return; + SetLocalInt(oCreature, AI_TALENTS_SET, TRUE); + object oModule = GetModule(); + ai_Counter_Start(); + ai_SetCreatureSpellTalents(oCreature, bMonster); + ai_Counter_End(GetName(oCreature) + ": Spell Talents"); + ai_SetCreatureSpecialAbilityTalents(oCreature, bMonster); + ai_Counter_End(GetName(oCreature) + ": Special Ability Talents"); + DeleteLocalJson(oCreature, AI_TALENT_IMMUNITY); + ai_SetCreatureItemTalents(oCreature, bMonster); + ai_Counter_End(GetName(oCreature) + ": Item Talents"); + if(GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS) && GetLocalInt(oModule, AI_RULE_PRESUMMON) && bMonster) + { + ai_TrySummonFamiliarTalent(oCreature); + ai_TrySummonAnimalCompanionTalent(oCreature); + } + // AI_CAT_CURE is setup differently we save the level as the highest. + //if(JsonGetType(GetLocalJson(oCreature, AI_TALENT_CURE)) != JSON_TYPE_NULL) SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE, 9); + // With spontaneous cure spells we need to clear this as the number of spells don't count. + //if(GetLevelByClass(CLASS_TYPE_CLERIC, oCreature)) SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_HEALING, 0); +} +int ai_UseSpontaneousCureTalentFromCategory(object oCreature, string sCategory, int nInMelee, int nDamage, object oTarget = OBJECT_INVALID) +{ + // Get the saved category from oCreature. + json jCategory = GetLocalJson(oCreature, sCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "2095", "jCategory: " + sCategory + " " + JsonDump(jCategory, 2)); + if(JsonGetType(jCategory) == JSON_TYPE_NULL) return FALSE; + int nLevel = 4; + // If there are no talents at lower levels then start at the lower level. + int nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + sCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "2100", AI_MAX_TALENT + sCategory + ": " + + IntToString(nMaxTalentLevel) + + " nLevel: " + IntToString(nLevel)); + if(nMaxTalentLevel < nLevel) nLevel = nMaxTalentLevel; + if(nLevel < 0 || nLevel > 5) nLevel = 4; + json jLevel, jTalent, jLevelSave; + int nTalentType, nTalentClass, nTalentSlot, nSpell; + int nSlotIndex, nMaxSlotIndex, nMaxNoTalentLevel, nSpellSave, nLevelSave, nSlotSave; + string sSpellName; + // Loop through nLevels down to nMinNoTalentLevel looking for the first talent + // (i.e. the highest or best?). + while(nLevel > -1) + { + // Get the array of nLevel cycling down to 0. + jLevel = JsonArrayGet(jCategory, nLevel); + nMaxSlotIndex = JsonGetLength(jLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "2116", "nLevel: " + IntToString(nLevel) + + " nMaxSlotIndex: " + IntToString(nMaxSlotIndex)); + if(nMaxSlotIndex > 0) + { + // Get the talent within nLevel cycling from the first to the last. + nSlotIndex = 0; + while (nSlotIndex < nMaxSlotIndex) + { + jTalent= JsonArrayGet(jLevel, nSlotIndex); + if(AI_DEBUG) ai_Debug("0i_talents", "2125", "nSlotIndex: " + IntToString(nSlotIndex) + + " jTalent Type: " + IntToString(JsonGetInt(JsonArrayGet(jTalent, 0)))); + nTalentType = JsonGetInt(JsonArrayGet(jTalent, 0)); + nTalentClass = JsonGetInt(JsonArrayGet(jTalent, 2)); + // We can only convert spells from the cleric class. + if(nTalentType == AI_TALENT_TYPE_SPELL && nTalentClass == CLASS_TYPE_CLERIC) + { + if(nLevel == 4) nSpell = SPELL_CURE_CRITICAL_WOUNDS; + else if(nLevel == 3) nSpell = SPELL_CURE_SERIOUS_WOUNDS; + else if(nLevel == 2) nSpell = SPELL_CURE_MODERATE_WOUNDS; + else if(nLevel == 1) nSpell = SPELL_CURE_LIGHT_WOUNDS; + else nSpell = 0; + if(AI_DEBUG) ai_Debug("0i_talents", "2137", "nSpell: " + IntToString(nSpell)); + if(nSpell) + { + if(ai_ShouldWeCastThisCureSpell(nSpell, nDamage)) + { + + nTalentSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + SetMemorizedSpellReady(oCreature, nTalentClass, nLevel, nTalentSlot, FALSE); + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(ai_GetIsCharacter(oCreature)) ai_SendMessages(GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_MAGENTA, oCreature); + if(AI_DEBUG) ai_Debug("0i_talents", "2148", GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + "."); + ActionCastSpellAtObject(nSpell, oTarget, 255, TRUE); + return TRUE; + } + // Save the lowest level cure spell as we might need to cast it. + else if(nLevel < nLevelSave) + { + jLevelSave = jLevel; + nLevelSave = nLevel; + nSlotSave = nTalentSlot; + nSpellSave = nSpell; + } + } + } + nSlotIndex++; + } + } + else SetLocalInt(oCreature, AI_MAX_TALENT + sCategory, nLevel - 1); + nLevel--; + } + // Did we find a spell? If we did then use it. + if(nSpellSave) + { + if(AI_DEBUG) ai_Debug("0i_talents", "2171", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + "."); + SetMemorizedSpellReady(oCreature, CLASS_TYPE_CLERIC, nLevelSave, nSlotSave, FALSE); + ai_RemoveTalent(oCreature, jCategory, jLevelSave, sCategory, nLevelSave, nSlotSave); + sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpellSave))); + if(ai_GetIsCharacter(oCreature)) ai_SendMessages(GetName(oCreature) + " has spontaneously cast " + sSpellName + " on " + GetName(oTarget) + ".", AI_COLOR_MAGENTA, oCreature); + ActionCastSpellAtObject(nSpellSave, oTarget, 255, TRUE); + return TRUE; + } + return FALSE; +} +int ai_UseCreatureSpellTalent(object oCreature, json jLevel, json jTalent, string sCategory, int nInMelee, object oTarget = OBJECT_INVALID) +{ + // Check for polymorph, spells cannot be used while polymorphed. + if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature)) return FALSE; + // Get the spells information so we can check if they still have it. + int nClass = JsonGetInt(JsonArrayGet(jTalent, 2)); + int nLevel = JsonGetInt(JsonArrayGet(jTalent, 3)); + int nSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + if(ai_IsSilenced(oCreature, JsonGetInt(JsonArrayGet(jTalent, 2)))) + { + if(GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot) != METAMAGIC_SILENT) + { + object oAOE = GetNearestObjectByTag("VFX_MOB_SILENCE", oCreature); + float fDistance = GetDistanceBetween(oAOE, oCreature); + if(fDistance != 0.0 && fDistance <= 4.0) + { + location lLocation = GetRandomLocation(GetArea(oCreature), oCreature, 5.0); + ai_ClearCreatureActions(); + if(AI_DEBUG) ai_Debug("0i_talents", "2225", GetName(oCreature) + " is moving out of a silence effect!"); + ActionMoveToLocation(lLocation, TRUE); + return TRUE; + } + else return FALSE; + } + } + if(ai_ArcaneSpellFailureTooHigh(oCreature, nClass, nLevel, nSlot)) return FALSE; + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + // Shouldn't need this anymore, we need to do a debug looking at this. + if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot) < 1) return FALSE; + if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget)) + { + if(ai_CompareLastAction(oCreature, AI_LAST_ACTION_CAST_SPELL)) return -1; + return TRUE; + } + return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "1629", "Known caster Level: " + IntToString(nLevel) + + " Uses : " + IntToString(GetSpellUsesLeft(oCreature, nClass, JsonGetInt(JsonArrayGet(jTalent, 1))))); + if(!GetSpellUsesLeft(oCreature, nClass, JsonGetInt(JsonArrayGet(jTalent, 1)))) return -2; + return ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget); +} +int ai_UseCreatureItemTalent(object oCreature, json jLevel, json jTalent, string sCategory, int nInMelee, object oTarget = OBJECT_INVALID) +{ + object oItem = StringToObject(JsonGetString(JsonArrayGet(jTalent, 2))); + int nItemType = GetBaseItemType(oItem); + // Check if the item is a potion since there are some special cases. + if(nItemType == BASE_ITEM_POTIONS || nItemType == BASE_ITEM_ENCHANTED_POTION) + { + // Potions cause attack of opportunities and this could be deadly! + // Removed for healing potions as that is one time you would use potions in melee. + if(sCategory != AI_TALENT_HEALING) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1925", "Using a non-healing potion nInMelee: " + IntToString(nInMelee)); + if(nInMelee > 1) return FALSE; + // Don't use potions on allies that are not within 3 meters. + if(GetDistanceBetween(oCreature, oTarget) > 3.1) return FALSE; + } + // For now we are allowing creatures to use "give" potions to others + // unless the player is using a healing potion and has party healing turned off. + else if(oCreature != oTarget && ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) return FALSE; + } + // Check for polymorph, only potions can be used while polymorphed. + else if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature)) return FALSE; + else if(nItemType == BASE_ITEM_HEALERSKIT) + { + if(!GetLocalInt(GetModule(), AI_RULE_HEALERSKITS)) return FALSE; + if(oCreature != oTarget && ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) return FALSE; + if(AI_DEBUG) ai_Debug("0i_talents", "1724", "Using " + GetName(oItem) + " nInMelee: " + IntToString(nInMelee) + + " targeting: " + GetName(oTarget)); + ai_SetLastAction(oCreature, AI_LAST_ACTION_USED_ITEM); + ActionUseItemOnObject(oItem, GetFirstItemProperty(oItem), oTarget); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + // We also must check for stack size. + if(GetItemStackSize(oItem) == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + return TRUE; + } + if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget)) return TRUE; + return FALSE; +} +int ai_UseCreatureTalent(object oCreature, string sCategory, int nInMelee, int nLevel = 10, object oTarget = OBJECT_INVALID) +{ + // Get the saved category from oCreature. + json jCategory = GetLocalJson(oCreature, sCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "2292", "jCategory: " + sCategory + " " + JsonDump(jCategory, 2)); + if(JsonGetType(jCategory) == JSON_TYPE_NULL) return FALSE; + // If there are no talents at lower levels then start at the lower level. + int nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + sCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "2297", AI_MAX_TALENT + sCategory + ": " + + IntToString(nMaxTalentLevel) + + " nLevel: " + IntToString(nLevel)); + if(nMaxTalentLevel < nLevel) nLevel = nMaxTalentLevel; + if(nLevel < 0 || nLevel > 10) nLevel = 9; + json jLevel, jTalent; + int nClass, nSlot, nType, nSlotIndex, nMaxSlotIndex, nTalentUsed, nSpell; + int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC); + int bUseMagicItems = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC_ITEMS); + if(AI_DEBUG) ai_Debug("0i_talents", "2305", "bUseMagic: " + IntToString(bUseMagic) + + " bUseMagicItems: " + IntToString(bUseMagicItems) + + " nLevel: " + IntToString(nLevel)); + // Loop through nLevels down to nMinNoTalentLevel looking for the first talent + // (i.e. the highest or best?). + while(nLevel > -1) + { + // Get the array of nLevel cycling down to 0. + jLevel = JsonArrayGet(jCategory, nLevel); + nMaxSlotIndex = JsonGetLength(jLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "2288", "nLevel: " + IntToString(nLevel) + + " nMaxSlotIndex: " + IntToString(nMaxSlotIndex)); + if(nMaxSlotIndex > 0) + { + // Get the talent within nLevel cycling from the first to the last. + nSlotIndex = 0; + while (nSlotIndex < nMaxSlotIndex) + { + jTalent= JsonArrayGet(jLevel, nSlotIndex); + if(AI_DEBUG) ai_Debug("0i_talents", "2300", "nSlotIndex: " + IntToString(nSlotIndex) + + " jTalent Type: " + IntToString(JsonGetInt(JsonArrayGet(jTalent, 0)))); + nType = JsonGetInt(JsonArrayGet(jTalent, 0)); + if(bUseMagic) + { + if(nType == AI_TALENT_TYPE_SPELL) + { + nTalentUsed = ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget); + // -1 means it was a memorized spell and we need to remove it. + if(nTalentUsed == -1) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + return TRUE; + } + else if(nTalentUsed == -2) + { + ai_RemoveTalentLevel(oCreature, jCategory, jLevel, sCategory, nLevel); + } + else if(nTalentUsed) return TRUE; + } + else if(nType == AI_TALENT_TYPE_SP_ABILITY) + { + // Special ability spells do not need to concentrate?! + if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget)) + { + // When the ability is used that slot is now not readied. + // Multiple uses of the same spell are stored in different slots. + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + return TRUE; + } + } + } + if(bUseMagicItems && nType == AI_TALENT_TYPE_ITEM) + { + // Items do not need to concentrate. + if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_talents", "2337", "Checking if Item is used up: " + + IntToString(JsonGetInt(JsonArrayGet(jTalent, 4)))); + if(JsonGetInt(JsonArrayGet(jTalent, 4)) == -1) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + } + return TRUE; + } + } + //else if(nType == AI_TALENT_TYPE_FEAT) {} + nSlotIndex++; + } + } + else SetLocalInt(oCreature, AI_MAX_TALENT + sCategory, nLevel - 1); + nLevel--; + } + return FALSE; +} +int ai_UseTalent(object oCreature, int nTalent, object oTarget) +{ + if(AI_DEBUG) ai_Debug("0i_talents", "1912", GetName(oCreature) + " is trying to use " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nTalent))) + + " on " + GetName(oTarget)); + // Get the saved category from oCreature. + string sCategory = Get2DAString("ai_spells", "Category", nTalent); + json jCategory = GetLocalJson(oCreature, sCategory); + if(AI_DEBUG) ai_Debug("0i_talents", "1917", "jCategory: " + sCategory + " " + JsonDump(jCategory, 2)); + if(JsonGetType(jCategory) == JSON_TYPE_NULL) return FALSE; + json jLevel, jTalent; + int nLevel, nClass, nSlot, nType, nSlotIndex, nMaxSlotIndex, nTalentUsed, nSpell; + // Loop through nLevels down to nMinNoTalentLevel looking for the first talent + // (i.e. the highest or best?). + while(nLevel <= 9) + { + // Get the array of nLevel. + jLevel = JsonArrayGet(jCategory, nLevel); + nMaxSlotIndex = JsonGetLength(jLevel); + if(AI_DEBUG) ai_Debug("0i_talents", "1925", "nLevel: " + IntToString(nLevel) + + " nMaxSlotIndex: " + IntToString(nMaxSlotIndex)); + if(nMaxSlotIndex > 0) + { + // Get the talent within nLevel cycling from the first to the last. + nSlotIndex = 0; + while (nSlotIndex < nMaxSlotIndex) + { + jTalent= JsonArrayGet(jLevel, nSlotIndex); + if(AI_DEBUG) ai_Debug("0i_talents", "1936", "nSlotIndex: " + IntToString(nSlotIndex) + + " jTalent Type: " + IntToString(JsonGetInt(JsonArrayGet(jTalent, 0)))); + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + if(nSpell == nTalent) + { + nType = JsonGetInt(JsonArrayGet(jTalent, 0)); + if(nType == AI_TALENT_TYPE_SPELL || nType == AI_TALENT_TYPE_SP_ABILITY) + { + if(ai_UseTalentOnObject(oCreature, jTalent, oTarget, 0)) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + return TRUE; + } + } + else if(nType == AI_TALENT_TYPE_ITEM) + { + // Items do not need to concentrate. + if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, sCategory, 0, oTarget)) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1955", "Checking if Item is used up: " + + IntToString(JsonGetInt(JsonArrayGet(jTalent, 4)))); + if(JsonGetInt(JsonArrayGet(jTalent, 4)) == -1) + { + ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex); + } + return TRUE; + } + } + } + nSlotIndex++; + } + } + nLevel++; + } + return FALSE; +} +int ai_UseTalentOnObject(object oCreature, json jTalent, object oTarget, int nInMelee) +{ + int nClass, nLevel, nSlot, nMetaMagic, nDomain; + int nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + int nType = JsonGetInt(JsonArrayGet(jTalent, 0)); + if(nType == AI_TALENT_TYPE_SPELL) + { + if(!ai_CastInMelee(oCreature, nSpell, nInMelee)) return FALSE; + nClass = JsonGetInt(JsonArrayGet(jTalent, 2)); + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + nLevel = JsonGetInt(JsonArrayGet(jTalent, 3)); + nSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + if(GetMemorizedSpellIsDomainSpell(oCreature, nClass, nLevel, nSlot) == 1) nDomain = nLevel; + else nDomain = 0; + nMetaMagic = GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot); + } + else + { + nMetaMagic = METAMAGIC_NONE; + nDomain = 0; + } + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell)) return TRUE; + } + else if(nType == AI_TALENT_TYPE_SP_ABILITY) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1790", GetName(oCreature) + " is using a special ability!"); + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + nClass = 255; + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell)) return TRUE; + } + else if(nType == AI_TALENT_TYPE_ITEM) + { + object oItem = StringToObject(JsonGetString(JsonArrayGet(jTalent, 2))); + int nBaseItemType = GetBaseItemType(oItem); + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell, nBaseItemType)) return TRUE; + int nIndex, nSubIndex = 0; + nSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + itemproperty ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + if(nIndex++ == nSlot) break; + ipProp = GetNextItemProperty(oItem); + } + // Cast items have the following: + // 1)Single_Use. + // 2-6) Charges/Use [Note: 7 is 0 charges per use]. + // 8-12) Uses/Day [Note: 13 is unlimited uses per day]. + // We set the slot to -1 to let the other function know we need this talent removed. + int nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses == 1) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1816", "Single Use item."); + if(AI_DEBUG) ai_Debug("0i_talents", "1817", "Stack size: " + IntToString(GetItemStackSize(oItem))); + // We also must check for stack size. + if(GetItemStackSize(oItem) == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + } + else if(nUses > 1 && nUses < 7) + { + int nCharges = GetItemCharges(oItem); + // If the item is equipable then do not use the last charge! + if(Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) != "0x00000") + { + if(nCharges <= 7 - nUses) return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "1824", "Item charges: " + IntToString(nCharges)); + if(nCharges < (7 - nUses) * 2) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1829", "Stack size: " + IntToString(GetItemStackSize(oItem))); + // We also must check for stack size. + if(GetItemStackSize(oItem) == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + } + } + else if(nUses > 7 && nUses < 13) + { + int nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(AI_DEBUG) ai_Debug("0i_talents", "1837", "Item uses: " + IntToString(nPerDay)); + if(nPerDay == 1) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1842", "Stack size: " + IntToString(GetItemStackSize(oItem))); + // We also must check for stack size. + if(GetItemStackSize(oItem) == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + } + } + // Lets not always use unlimited items! + else if(nUses == 7 || nUses == 13) + { + if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + } + ai_SetLastAction(oCreature, nSpell); + ActionUseItemOnObject(oItem, ipProp, oTarget, nSubIndex); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + if(AI_DEBUG) ai_Debug("0i_talents", "1850", GetName(oCreature) + " is using " + GetName(oItem) + " on " + GetName(oTarget)); + return TRUE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "1853", "nMetaMagic: " + IntToString(nMetaMagic) + + " nDomain: " + IntToString(nDomain) + " nClass: " + IntToString(nClass)); + ai_SetLastAction(oCreature, nSpell); + ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, FALSE, nDomain, 0, FALSE, nClass, FALSE); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + if(AI_DEBUG) + { + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + ai_Debug("0i_talents", "1859", GetName(oCreature) + " is casting " + sSpellName + " on " + GetName(oTarget)); + } + return TRUE; +} +int ai_UseTalentAtLocation(object oCreature, json jTalent, object oTarget, int nInMelee) +{ + int nSpell, nClass, nLevel, nSlot, nMetaMagic, nDomain; + int nType = JsonGetInt(JsonArrayGet(jTalent, 0)); + if(nType == AI_TALENT_TYPE_SPELL) + { + if(!ai_CastInMelee(oCreature, nSpell, nInMelee)) return FALSE; + nClass = JsonGetInt(JsonArrayGet(jTalent, 2)); + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + nLevel = JsonGetInt(JsonArrayGet(jTalent, 3)); + nSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + if(GetMemorizedSpellIsDomainSpell(oCreature, nClass, nLevel, nSlot) == 1) nDomain = nLevel; + else nDomain = 0; + nMetaMagic = GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot); + } + else + { + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + nMetaMagic = METAMAGIC_NONE; + nDomain = 0; + } + } + else if(nType == AI_TALENT_TYPE_SP_ABILITY) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1888", GetName(oCreature) + " is using a special ability!"); + nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + nClass = 255; + } + else if(nType == AI_TALENT_TYPE_ITEM) + { + object oItem = StringToObject(JsonGetString(JsonArrayGet(jTalent, 2))); + int nBaseItemType = GetBaseItemType(oItem); + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell, nBaseItemType)) return TRUE; + int nIndex; + int nSubIndex = JsonGetInt(JsonArrayGet(jTalent, 3));; + nSlot = JsonGetInt(JsonArrayGet(jTalent, 4)); + itemproperty ipProp = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProp)) + { + if(nIndex++ == nSlot) break; + ipProp = GetNextItemProperty(oItem); + } + // Cast items have the following: + // 1)Single_Use. + // 2-6) Charges/Use [Note: 7 is 0 charges per use]. + // 8-12) Uses/Day [Note: 13 is unlimited uses per day]. + // We set the slot to -1 to let the other function know we need this talent removed. + int nUses = GetItemPropertyCostTableValue(ipProp); + if(nUses == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + else if(nUses > 1 && nUses < 7) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1915", "Item charges: " + IntToString(GetItemCharges(oItem))); + int nCharges = GetItemCharges(oItem); + // If the item is equipable then do not use the last charge! + if(Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) != "0x00000") + { + if(nCharges <= 7 - nUses) return FALSE; + } + if(AI_DEBUG) ai_Debug("0i_talents", "1824", "Item charges: " + IntToString(nCharges)); + if(nCharges < (7 - nUses) * 2) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1829", "Stack size: " + IntToString(GetItemStackSize(oItem))); + // We also must check for stack size. + if(GetItemStackSize(oItem) == 1) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + } + } + else if(nUses > 7 && nUses < 13) + { + if(AI_DEBUG) ai_Debug("0i_talents", "1923", "Item uses: " + IntToString(GetItemPropertyUsesPerDayRemaining(oItem, ipProp))); + int nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp); + if(nUses == 8 && nPerDay == 1 || nUses == 9 && nPerDay < 4 || + nUses == 10 && nPerDay < 6 || nUses == 11 && nPerDay < 8 || + nUses == 12 && nPerDay < 10) JsonArrayInsertInplace(jTalent, JsonInt(-1), 4); + } + // Lets not always use unlimited items! + else if(nUses == 7 || nUses == 13) + { + if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + } + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell)) return TRUE; + ai_SetLastAction(oCreature, nSpell); + ActionUseItemAtLocation(oItem, ipProp, GetLocation(oTarget), nSubIndex); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + if(AI_DEBUG) ai_Debug("0i_talents", "1934", GetName(oCreature) + " is using " + GetName(oItem) + " at a location."); + return TRUE; + } + if(ai_CheckCombatPosition(oCreature, oTarget, nInMelee, nSpell)) return TRUE; + ai_SetLastAction(oCreature, nSpell); + ActionCastSpellAtLocation(nSpell, GetLocation(oTarget), nMetaMagic, FALSE, 0, FALSE, nClass, FALSE, nDomain); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(AI_DEBUG) ai_Debug("0i_talents", "1943", GetName(oCreature) + " is casting " + sSpellName + " at a location!"); + return TRUE; +} +int ai_CheckSpecialTalentsandUse(object oCreature, json jTalent, string sCategory, int nInMelee, object oTarget) +{ + int nSpell = JsonGetInt(JsonArrayGet(jTalent, 1)); + if(AI_DEBUG) ai_Debug("0i_talents", "1949", "nSpell: " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))) + + " sCategory: " + sCategory); + if(sCategory == AI_TALENT_DISCRIMINANT_AOE) + { + //ai_Debug("0i_talents", "1953", "CompareLastAction: " + + // IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + //if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + // Check to see if Disjunction should *not* be cast. + if(nSpell == SPELL_MORDENKAINENS_DISJUNCTION) + { + // Our master does not want us using any type of dispel! + if(ai_GetMagicMode(oCreature, AI_MAGIC_STOP_DISPEL)) return FALSE; + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + // Get the biggest group we can. + string sIndex = IntToString(ai_GetHighestMeleeIndexNotInAOE(oCreature)); + oTarget = GetLocalObject(oCreature, AI_ENEMY + sIndex); + if(!ai_CreatureHasDispelableEffect(oCreature, oTarget)) return FALSE; + // Maybe we should do an area of effect instead? + int nEnemies = ai_GetNumOfEnemiesInRange(oTarget, 5.0); + if(nEnemies > 2) + { + if(ai_UseTalentAtLocation(oCreature, jTalent, oTarget, nInMelee)) return TRUE; + } + } + // These spells have a Range of Personal i.e. cast on themselves, and + // an Area of Effect of Colossal (10.0). + else if(nSpell == SPELL_FIRE_STORM || nSpell == SPELL_STORM_OF_VENGEANCE) + { + // Make sure we have enough enemies to use this on. + int nEnemies = ai_GetNumOfEnemiesInRange(oCreature, 10.0); + if(nEnemies < 2) return FALSE; + // Get the nearest target to check defenses on. + oTarget = ai_GetNearestTarget(oCreature, 10.0); + if(!ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + if(ai_UseTalentAtLocation(oCreature, jTalent, oTarget, nInMelee)) return TRUE; + } + else if(nSpell == SPELL_UNDEATH_TO_DEATH) + { + float fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + int nUndead = ai_GetRacialTypeCount(oCreature, RACIAL_TYPE_UNDEAD, fRange); + if(nUndead < 3) return FALSE; + oTarget = ai_GetLowestCRRacialTarget(oCreature, RACIAL_TYPE_UNDEAD, fRange); + } + // Get a target for discriminant spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_CheckForGroupedTargetNotInAOE(oCreature, fRange); + } + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget) || + !ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + } + else if(sCategory == AI_TALENT_INDISCRIMINANT_AOE) + { + //ai_Debug("0i_talents", "1991", "CompareLastAction: " + + // IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + //if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + // These spells have a Range of Personal i.e. cast on themselves, and + // an Area of Effect of Colossal (10.0). + if(nSpell == SPELL_METEOR_SWARM) + { + // Make sure we have enough enemies and few allies to hit. + int nAllies = ai_GetNumOfAlliesInGroup(oCreature, 10.0); + int nEnemies = ai_GetNumOfEnemiesInRange(oCreature, 10.0); + if(nAllies > 1 || nEnemies < 2) return FALSE; + // Get the nearest target to check defenses on. + oTarget = ai_GetNearestTarget(oCreature, 10.0); + if(!ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + if(ai_UseTalentAtLocation(oCreature, jTalent, oCreature, nInMelee)) return TRUE; + } + // Get a target for indiscriminant spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + float fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_CheckForGroupedTargetNotInAOE(oCreature, fRange); + // Check for the number of allies, if there are too many then skip. + if(oTarget == OBJECT_INVALID) return FALSE; + int nRoll = d6() + 1; + if(GetAssociateType(oCreature)) nRoll = d3(); + int nAllies = ai_GetNumOfAlliesInGroup(oTarget, AI_RANGE_CLOSE); + if(AI_DEBUG) ai_Debug("0i_talents", "2084", "Num of Allies in range: " + IntToString(nAllies)+ + " < nRoll: " + IntToString(nRoll)); + if(nAllies >= nRoll) return FALSE; + } + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget) || + !ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + //********************************************************************** + //********** These spells are checked after picking a target *********** + //********************************************************************** + // Check if the Sleep spells are being used appropriately. + if(nSpell == SPELL_SLEEP) + { + if(GetHitDice(oTarget) > 4) return FALSE; + } + // Lets only use silence on casters. + else if(nSpell == SPELL_SILENCE) + { + if(!ai_CheckClassType(oTarget, AI_CLASS_TYPE_CASTER)) + { + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER); + if(oTarget == OBJECT_INVALID) return FALSE; + } + } + } + else if(sCategory == AI_TALENT_RANGED) + { + //ai_Debug("0i_talents", "2045", "CompareLastAction: " + + // IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + //if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + // Check to see if Dispel Magic and similar spells should *not* be cast + if(nSpell == SPELL_DISPEL_MAGIC || nSpell == SPELL_LESSER_DISPEL || + nSpell == SPELL_GREATER_DISPELLING) + { + // Our master does not want us using any type of dispel! + if(ai_GetMagicMode(oCreature, AI_MAGIC_STOP_DISPEL)) return FALSE; + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + // Lets get a caster as they should have more buffs. + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, fRange); + // No caster then get the most powerful enemy! + if(oTarget == OBJECT_INVALID) oTarget = ai_GetHighestCRTarget(oCreature, fRange); + if(oTarget != OBJECT_INVALID) + { + if(!ai_CreatureHasDispelableEffect(oCreature, oTarget)) return FALSE; + // Maybe we should do an area of effect instead? + int nEnemies = ai_GetNumOfEnemiesInRange(oTarget, 5.0); + if(nEnemies > 2) + { + if(ai_UseTalentAtLocation(oCreature, jTalent, oTarget, nInMelee)) return TRUE; + } + } + if(oTarget == OBJECT_INVALID) return FALSE; + } + // Make sure the spell will work on the target. + else if(nSpell == SPELL_HOLD_PERSON || nSpell == SPELL_DOMINATE_PERSON || + nSpell == SPELL_CHARM_PERSON) + { + if(oTarget != OBJECT_INVALID) + { + int nRaceType = GetRacialType(oTarget); + if(AI_DEBUG) ai_Debug("0i_talents", "2075", " Person Spell race: " + IntToString(nRaceType)); + if((nRaceType > 6 && nRaceType < 12) || nRaceType > 15) oTarget = OBJECT_INVALID; + } + if(oTarget == OBJECT_INVALID) + { + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_GetNearestRacialTarget(oCreature, AI_RACIAL_TYPE_HUMANOID, fRange); + if(oTarget == OBJECT_INVALID) return FALSE; + } + } + else if(nSpell == SPELL_HOLD_ANIMAL || nSpell == SPELL_DOMINATE_ANIMAL) + { + if(oTarget != OBJECT_INVALID) + { + if(GetRacialType(oTarget) != RACIAL_TYPE_ANIMAL) oTarget = OBJECT_INVALID; + } + if(oTarget == OBJECT_INVALID) + { + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_GetNearestRacialTarget(oCreature, AI_RACIAL_TYPE_ANIMAL_BEAST, fRange); + if(oTarget == OBJECT_INVALID) return FALSE; + } + } + // Get a target for ranged spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_GetSpellTargetBasedOnSaves(oCreature, nSpell, fRange); + } + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget) || + !ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + //********************************************************************** + //********** These spells are checked after picking a target *********** + //********************************************************************** + // Don't use Domination spells on players! They don't work. + if((nSpell == SPELL_DOMINATE_MONSTER || nSpell == SPELL_DOMINATE_PERSON)) + { + if(ai_GetIsCharacter(oTarget)) return FALSE; + } + // Check to see if they have the shield spell up. + else if(nSpell == SPELL_MAGIC_MISSILE) + { + if(GetHasSpellEffect(SPELL_SHIELD, oTarget)) return FALSE; + } + // Scare only works on 5 hitdice or less. + else if(nSpell == SPELL_SCARE) + { + if(GetHitDice(oTarget) > 5) return FALSE; + } + // Don't use drown against nonliving opponents. + else if(nSpell == SPELL_DROWN) + { + if(ai_IsNonliving(GetRacialType(oTarget))) return FALSE; + } + // Don't use Power Word Kill on Targets with more than 100hp + else if(nSpell == SPELL_POWER_WORD_KILL) + { + if(GetCurrentHitPoints(oTarget) <= 100) return FALSE; + } + } + else if(sCategory == AI_TALENT_TOUCH) + { + //ai_Debug("0i_talents", "2139", "CompareLastAction: " + + // IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + //if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + // Get a target for touch spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + oTarget = ai_GetSpellTargetBasedOnSaves(oCreature, nSpell, AI_RANGE_MELEE); + } + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget) || + !ai_CastOffensiveSpellVsTarget(oCreature, oTarget, nSpell) || + ai_CreatureImmuneToEffect(oCreature, oTarget, nSpell)) return FALSE; + } + else if(sCategory == AI_TALENT_HEALING) + { + int nHpLost = ai_GetPercHPLoss(oTarget); + // If the target is bloody then just use the best we have! + if(nHpLost > AI_HEALTH_BLOODY) + { + // Make sure we should use a mass heal on us or an ally! + // Two allies need healing or one is almost dead to use mass heal! + if(nSpell == SPELL_MASS_HEAL) + { + int bWoundedAlly; + object oAlly = ai_GetNearestAlly(oTarget); + if(oAlly != OBJECT_INVALID) + { + // If we don't have a nearby ally that needs healed then skip. + if(ai_GetPercHPLoss(oAlly) > AI_HEALTH_WOUNDED || + GetDistanceBetween(oCreature, oAlly) > 9.0f) return FALSE; + } + } + // Make sure they have taken enough damage. + int nHpDmg = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if(!ai_ShouldWeCastThisCureSpell(nSpell, nHpDmg)) return FALSE; + } + } + else if(sCategory == AI_TALENT_ENHANCEMENT) + { + if(AI_DEBUG) ai_Debug("0i_talents", "2713", "CompareLastAction: " + + IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + if(nSpell == SPELL_INVISIBILITY || nSpell == SPELL_SANCTUARY) + { + // Lets not run past an enemy to cast an enhancement unless we have + // the ability to move in combat, bad tactics! + float fRange; + if(ai_CanIMoveInCombat(oCreature)) fRange = AI_RANGE_PERCEPTION; + else + { + fRange = GetDistanceBetween(oCreature, GetLocalObject(oCreature, AI_ENEMY_NEAREST)) - 3.0f; + // Looks bad when your right next to an ally, but technically the enemy is closer. + if(fRange < AI_RANGE_MELEE) fRange = AI_RANGE_MELEE; + } + oTarget = ai_GetAllyToHealTarget(oCreature, fRange); + if(oTarget != OBJECT_INVALID) + { + int nHp = ai_GetPercHPLoss(oTarget); + int nHpLimit = ai_GetHealersHpLimit(oCreature); + if(nHp > nHpLimit) return FALSE; + } + } + if(nSpell == SPELL_PRAYER) + { + int nEnemies = ai_GetNumOfEnemiesInRange(oCreature, 10.0); + int nAllies = ai_GetNumOfAlliesInGroup(oCreature, 10.0); + if(nEnemies + nAllies < 5) return FALSE; + oTarget = oCreature; + } + // Since haste does not have an effect when it comes from items when we + // check for item properties we set this variable so we know they have it. + else if(nSpell == SPELL_HASTE && GetLocalInt(oCreature, sIPHasHasteVarname)) return FALSE; + // Only reason to cast Ultravision(Darkvision) in combat is if a Darkness + // spell is nearby. + else if(nSpell == SPELL_DARKVISION) + { + int nCnt = 1, bCastSpell; + string sAOEType; + object oAOE = GetNearestObject(OBJECT_TYPE_AREA_OF_EFFECT, oCreature, nCnt); + while(oAOE != OBJECT_INVALID && GetDistanceBetween(oCreature, oAOE) <= AI_RANGE_PERCEPTION) + { + // AOE's have the tag set to the "LABEL" in vfx_persistent.2da + sAOEType = GetTag(oAOE); + if(AI_DEBUG) ai_Debug("0i_talents", "2759", "Ultravision check; AOE tag: " + sAOEType); + if(sAOEType == "VFX_PER_DARKNESS") + { + if(!GetHasFeat(FEAT_DARKVISION)) bCastSpell = TRUE; + break; + } + oAOE = GetNearestObject(OBJECT_TYPE_AREA_OF_EFFECT, oCreature, ++nCnt); + } + if(!bCastSpell) return FALSE; + } + // Get a target for enhancement spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + // Get talents range and target. + float fRange = ai_GetSpellRange(nSpell); + // Personal spell + if(fRange == 0.1f) oTarget = oCreature; + // Range/Touch spell + else oTarget = ai_GetAllyBuffTarget(oCreature, nSpell, fRange); + } + if(AI_DEBUG) ai_Debug("0i_talents", "2260", " oTarget: " + GetName(oTarget) + + " HasSpellEffect: " + IntToString(GetHasSpellEffect(nSpell, oTarget))); + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget)) return FALSE; + //********************************************************************** + //********** These spells are checked after picking a target *********** + //********************************************************************** + // Weapon enhancing spells only work on melee weapons! + if(nSpell == SPELL_MAGIC_WEAPON || nSpell == SPELL_GREATER_MAGIC_WEAPON || + nSpell == SPELL_BLESS_WEAPON || nSpell == SPELL_FLAME_WEAPON || + nSpell == SPELL_DARKFIRE) + { + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + if(!ai_GetIsMeleeWeapon(oWeapon)) return FALSE; + } + // Should we ignore associates? + if(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + } + else if(sCategory == AI_TALENT_PROTECTION) + { + if(AI_DEBUG) ai_Debug("0i_talents", "2281", "CompareLastAction: " + + IntToString(ai_CompareLastAction(oCreature, nSpell))); + // If we used this spell talent last round then don't use it this round. + if(ai_CompareLastAction(oCreature, nSpell)) return FALSE; + // Stone bones only effects the undead. + if(nSpell == SPELL_STONE_BONES) + { + if(oTarget != OBJECT_INVALID) + { + if(GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) oTarget = OBJECT_INVALID; + } + if(oTarget == OBJECT_INVALID) + { + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + oTarget = ai_GetNearestRacialTarget(oCreature, RACIAL_TYPE_UNDEAD, fRange); + if(oTarget == OBJECT_INVALID) return FALSE; + } + } + else if(nSpell == SPELL_MAGIC_FANG) + { + oTarget = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCreature); + if(oTarget == OBJECT_INVALID) return FALSE; + } + // Lets see if we should cast resistances in our current situation, + // lets check for enemy casters that may have energy damaging spells, or energy weapons. + else if(nSpell == SPELL_ENDURE_ELEMENTS || nSpell == SPELL_PROTECTION_FROM_ELEMENTS || + nSpell == SPELL_RESIST_ELEMENTS || nSpell == SPELL_ENERGY_BUFFER) + { + int bCastSpell; + object oEnemy = ai_GetEnemyAttackingMe(oCreature); + if(oEnemy != OBJECT_INVALID) + { + object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oEnemy); + if(oWeapon == OBJECT_INVALID) oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oEnemy); + if(oWeapon == OBJECT_INVALID) oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oEnemy); + if(AI_DEBUG) ai_Debug("0i_talents", "2812", GetName(oEnemy) + " is using weapon: " + GetName(oWeapon)); + if(oWeapon != OBJECT_INVALID) + { + itemproperty nProperty = GetFirstItemProperty(oWeapon); + while(GetIsItemPropertyValid(nProperty)) + { + if(GetItemPropertyType(nProperty) == ITEM_PROPERTY_DAMAGE_BONUS) + { + int nSubType = GetItemPropertySubType(nProperty); + if(AI_DEBUG) ai_Debug("0i_talents", "2821", GetName(oWeapon) + " has PropertySubType: " + + IntToString(nSubType) + " If equals [6,7,9,10,13] don't cast!"); + if(nSubType == 6 || nSubType == 7 || nSubType == 9 || + nSubType == 10 || nSubType == 13) + { + bCastSpell = TRUE; + break; + } + } + nProperty = GetNextItemProperty(oWeapon); + } + } + } + if(ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER) != OBJECT_INVALID) bCastSpell = TRUE; + if(!bCastSpell) return FALSE; + } + // Get a target for protection spells if one is not already set. + if(oTarget == OBJECT_INVALID) + { + // Get talents range and target. + float fRange = ai_GetSpellRange(nSpell); + // Personal spell + if(fRange == 0.1f) oTarget = oCreature; + // Range/Touch spell + else oTarget = ai_GetAllyBuffTarget(oCreature, nSpell, fRange); + } + if(oTarget == OBJECT_INVALID || GetHasSpellEffect(nSpell, oTarget)) return FALSE; + //********************************************************************** + //********** These spells are checked after picking a target *********** + //********************************************************************** + // Don't double up Stoneskin, Ghostly visage, or Ethereal visage. + if(nSpell == SPELL_GHOSTLY_VISAGE || nSpell == SPELL_ETHEREAL_VISAGE || + nSpell == SPELL_STONESKIN) + { + if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget) || + GetHasSpellEffect(SPELL_STONESKIN, oTarget) || + GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget)) return FALSE; + } + // Don't use displacement if we are invisible! + else if(nSpell == SPELL_DISPLACEMENT) + { + if(GetHasSpellEffect(SPELL_INVISIBILITY, oTarget) || + GetHasSpellEffect(SPELL_IMPROVED_INVISIBILITY, oTarget) || + GetHasSpellEffect(SPELL_INVISIBILITY_SPHERE, oTarget) || + GetHasSpellEffect(SPELL_DISPLACEMENT, oTarget)) return FALSE; + } + // Should we ignore associates? + if(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && + GetAssociateType(oTarget) > 1) return FALSE; + } + else if(sCategory == AI_TALENT_SUMMON) + { + if(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCreature) != OBJECT_INVALID) return FALSE; + if(oTarget == OBJECT_INVALID) + { + /* Removed for now, summons creature in location that enemy was... looks bad. + float fRange; + if(nInMelee) fRange = AI_RANGE_MELEE; + else fRange = ai_GetOffensiveSpellSearchRange(oCreature, nSpell); + // Select lowest enemy combat target for summons. + oTarget = ai_GetLowestCRTarget(oCreature, fRange); + if(oTarget == OBJECT_INVALID) oTarget = oCreature; + */ + oTarget = oCreature; + if(ai_UseTalentAtLocation(oCreature, jTalent, oTarget, nInMelee)) + { + DelayCommand(4.0, ai_NameAssociate(oCreature, ASSOCIATE_TYPE_SUMMONED, "")); + return TRUE; + } + } + } + else if(sCategory == AI_TALENT_CURE) + { + } + if(ai_UseTalentOnObject(oCreature, jTalent, oTarget, nInMelee)) return TRUE; + return FALSE; +} diff --git a/src/module/nss/0i_time.nss b/src/module/nss/0i_time.nss new file mode 100644 index 0000000..3052ea6 --- /dev/null +++ b/src/module/nss/0i_time.nss @@ -0,0 +1,95 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_time +//////////////////////////////////////////////////////////////////////////////// + Include script for handling all time functions for the server. + + Lokey's functions: +int GetPosixTimestamp(); +string GetCurrentDateTime(); + +*/////////////////////////////////////////////////////////////////////////////// +// RETURNS a Timestamp in seconds since 1970-01-01. +int GetCurrentTimeInSeconds(); +// RETURNS a formated date, good for timestamping logs and text. +string GetCurrentDateTime(); +// Sends a server shutdown message 1800 seconds i.e 30 minutes before. +// nDuration is in seconds. i.e. one hours is 3600 defaults to 24 hours (86400). +// Should be put into the servers OnHeartBeat. +void CheckServerShutdownMessage(int nDuration = 86400); + +int GetCurrentTimeInSeconds() +{ + string stmt = "SELECT strftime('%s','now');"; + sqlquery sqlQuery = SqlPrepareQueryObject(GetModule(), stmt); + SqlStep(sqlQuery); + return SqlGetInt(sqlQuery, 0); +} +string GetCurrentDateTime() +{ + string stmt = "SELECT datetime('now', 'localtime')"; + sqlquery sqlQuery = SqlPrepareQueryObject(GetModule(), stmt); + SqlStep(sqlQuery); + return SqlGetString(sqlQuery, 0); +} +/// @addtogroup time Time +/// @brief Provides various time related functions. +/// @brief Returns the current time formatted according to the provided sqlite date time format string. +/// @param format Format string as used by sqlites STRFTIME(). +/// @return The current time in the requested format. Empty string on error. +string SQLite_GetFormattedSystemTime(string format); +/// @return Returns the number of seconds since midnight on January 1, 1970. +int SQLite_GetTimeStamp(); +/// @return Returns the number of milliseconds since midnight on January 1, 1970. +int SQLite_GetTimeMilliseconds(); +/// @brief A millisecond timestamp +struct SQLite_MillisecondTimeStamp +{ + int seconds; ///< Seconds since epoch + int milliseconds; ///< Milliseconds +}; +/// @remark For mircosecond timestamps use NWNX_Utility_GetHighResTimeStamp(). +/// @return Returns the number of milliseconds since midnight on January 1, 1970. +struct SQLite_MillisecondTimeStamp SQLite_GetMillisecondTimeStamp(); +/// @brief Returns the current date. +/// @return The date in the format (mm/dd/yyyy). +string SQLite_GetSystemDate(); +/// @brief Returns current time. +/// @return The current time in the format (24:mm:ss). +string SQLite_GetSystemTime(); +/// @} +string SQLite_GetFormattedSystemTime(string format) +{ + sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME(@format, 'now', 'localtime')"); + SqlBindString(query, "@format", format); + SqlStep(query); // sqlite returns NULL for invalid format in STRFTIME() + return SqlGetString(query, 0); +} +int SQLite_GetTimeStamp() +{ + sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME('%s', 'now')"); + SqlStep(query); + return SqlGetInt(query, 0); +} +int SQLite_GetTimeMillisecond() +{ + sqlquery query = SqlPrepareQueryObject(GetModule(), "select cast((julianday('now') - 2440587.5) * 86400 * 1000 as integer)"); + SqlStep(query); + return SqlGetInt(query, 0); +} +struct SQLite_MillisecondTimeStamp SQLite_GetMillisecondTimeStamp() +{ + sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME('%s', 'now'), SUBSTR(STRFTIME('%f', 'now'), 4)"); + SqlStep(query); + struct SQLite_MillisecondTimeStamp t; + t.seconds = SqlGetInt(query, 0); + t.milliseconds = SqlGetInt(query, 1); + return t; +} +string SQLite_GetSystemDate() +{ + return SQLite_GetFormattedSystemTime("%m/%d/%Y"); +} +string SQLite_GetSystemTime() +{ + return SQLite_GetFormattedSystemTime("%H:%M:%S"); +} diff --git a/src/module/nss/ai_a_ambusher.nss b/src/module/nss/ai_a_ambusher.nss new file mode 100644 index 0000000..f3f424b --- /dev/null +++ b/src/module/nss/ai_a_ambusher.nss @@ -0,0 +1,105 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_ambusher +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to ambush creatures by hiding or turning invisible. + OBJECT_SELF is the creature running the ai. + * This assumes we are not invisible since the ai_a_invisible script should fire if we are. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "19", GetName(oCreature) + " is using ambusher tactics: " + + " oNearestEnemy: " + GetName(oNearestEnemy) + " fDistance: " + + FloatToString(GetDistanceBetween(oNearestEnemy, oCreature), 0, 2)); + if(GetDistanceBetween(oNearestEnemy, oCreature) > AI_RANGE_CLOSE) + { + // Has our master told us to not use magic? + if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) + { + // If can turn invisible then we should probably do that! + if(ai_UseTalent(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY_SPHERE, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_SANCTUARY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_ETHEREALNESS, oCreature)) return; // Greater Sanctuary + if(ai_UseTalent(oCreature, SPELLABILITY_AS_IMPROVED_INVISIBLITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELLABILITY_AS_INVISIBILITY, oCreature)) return; + } + } + // Check the battle field to see if anyone see us? + int nEnemyIndex = ai_GetNearestIndexThatSeesUs(oCreature); + // If seen, can we try to hide now? + if(nEnemyIndex) + { + // Check for an attacker and can they see through invisibility? + object oAttacker = ai_GetEnemyAttackingMe(oCreature); + int bCanSeeInvisible; + if(oAttacker != OBJECT_INVALID) + { + bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_SEEINVISIBLE); + if(!bCanSeeInvisible) bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_TRUESEEING); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_5_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_10_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_60_FEET, oCreature); + } + if(!bCanSeeInvisible) + { + if(GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oCreature)) + { + if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "55", GetName(oCreature) + " is using hide in plain sight!"); + ClearAllActions(TRUE); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + return; + } + } + // Does not have hide in plain sight. + else + { + string sEnemyIndex = IntToString(nEnemyIndex); + float fEnemyDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + sEnemyIndex); + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "66", "fDistance: " + FloatToString(fEnemyDistance, 0, 2)); + if(fEnemyDistance > 20.0) + { + int bTried = GetLocalInt(oCreature, AI_TRIED_TO_HIDE); + if(!bTried) + { + // Move away so we can hide. + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "73", GetName(oCreature) + " is trying to move away to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + object oEnemy = GetLocalObject(oCreature, AI_ENEMY + sEnemyIndex); + ActionMoveAwayFromObject(oEnemy, TRUE, AI_RANGE_BATTLEFIELD); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + else SetLocalInt(oCreature, AI_TRIED_TO_HIDE, GetLocalInt(oCreature, AI_TRIED_TO_HIDE) - 1); + } + // We have been seen by an enemy near us so drop stealth. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + } + // The enemy can see through stealth so lets drop it. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + // We are not in stealth mode so and no one sees us so lets hide. + else if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + // Use any hiding talents we have + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "97", GetName(oCreature) + " is trying to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + // If we have givin up on stealth do our normal actions. + string sScript = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + if(sScript == "ai_a_ambusher" || sScript == "") sScript = "ai_a_default"; + if(AI_DEBUG) ai_Debug("ai_a_ambusher", "101", "Executing Script: " + sScript); + ExecuteScript(sScript, oCreature); +} diff --git a/src/module/nss/ai_a_atk_casters.nss b/src/module/nss/ai_a_atk_casters.nss new file mode 100644 index 0000000..362ba4b --- /dev/null +++ b/src/module/nss/ai_a_atk_casters.nss @@ -0,0 +1,159 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_atk_casters +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to the nearest casting creatures. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy. + 2 - Check for healing and curing first. + 3 - Check moral if wounded and this is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff or summons if this is a difficult+ battle. + 6 - Check for a Class ability and an offensive spell if this is a simple+ battle. + 7 - Check for a physical attack. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + int bAlwaysAtk = !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK); + if(AI_DEBUG) ai_Debug("ai_a_atk_casters", "80", "Check for ranged attack on nearest casting enemy!"); + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the nearest targets first. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("ai_a_atk_casters", "119", "Check for melee attack on nearest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) + { + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget == OBJECT_INVALID) + { + // Are we in melee? If so try to get the nearest enemy in melee. + if(nInMelee > 0) + { + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk); + // If we didn't get a target then get any target within range. + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk); + } + // If not then lets go find someone to attack! + else + { + // Get the nearest enemy. + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk); + // If we didn't get a target then get any target within range. + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk); + } + } + } + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("ai_a_atk_casters", "149", GetName(oTarget) + " is the nearest target for melee combat!"); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + if(AI_DEBUG) ai_Debug("ai_a_atk_casters", "154", "Do melee attack against (caster/nearest): " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} + diff --git a/src/module/nss/ai_a_atk_nearest.nss b/src/module/nss/ai_a_atk_nearest.nss new file mode 100644 index 0000000..1261dc7 --- /dev/null +++ b/src/module/nss/ai_a_atk_nearest.nss @@ -0,0 +1,80 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_atk_nearest +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to the nearest target. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy. + 2 - Check for healing and curing first. + 3 - Check moral if wounded and this is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff or summons if this is a difficult+ battle. + 6 - Check for a Class ability and an offensive spell if this is a simple+ battle. + 7 - Check for a physical attack. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + ai_DoPhysicalAttackOnNearest(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); +} + diff --git a/src/module/nss/ai_a_atk_warrior.nss b/src/module/nss/ai_a_atk_warrior.nss new file mode 100644 index 0000000..4821e53 --- /dev/null +++ b/src/module/nss/ai_a_atk_warrior.nss @@ -0,0 +1,159 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_atk_warrior +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to the nearest casting creatures. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy. + 2 - Check for healing and curing first. + 3 - Check moral if wounded and this is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff or summons if this is a difficult+ battle. + 6 - Check for a Class ability and an offensive spell if this is a simple+ battle. + 7 - Check for a physical attack. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + int bAlwaysAtk = !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK); + if(AI_DEBUG) ai_Debug("0i_actions", "496", "Check for ranged attack on nearest casting enemy!"); + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the nearest targets first. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("ai_a_atk_warrior", "119", "Check for melee attack on nearest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) + { + object oPCTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + if(oPCTarget == OBJECT_INVALID) + { + // Are we in melee? If so try to get the nearest enemy in melee. + if(nInMelee > 0) + { + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk); + // If we didn't get a target then get any target within range. + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk); + } + // If not then lets go find someone to attack! + else + { + // Get the nearest enemy. + oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk); + // If we didn't get a target then get any target within range. + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk); + } + } + } + // We might not have a target this is fine as sometimes we don't want to attack! + if(AI_DEBUG) ai_Debug("ai_a_atk_warrior", "149", GetName(oTarget) + " is the nearest target for melee combat!"); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + if(AI_DEBUG) ai_Debug("ai_a_atk_warrior", "154", "Do melee attack against (caster/nearest): " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} + diff --git a/src/module/nss/ai_a_barbarian.nss b/src/module/nss/ai_a_barbarian.nss new file mode 100644 index 0000000..12521c9 --- /dev/null +++ b/src/module/nss/ai_a_barbarian.nss @@ -0,0 +1,87 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_barbarian +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Barbarian class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oTarget; + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature)) + { + //************************* HEALING & CURES ************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // ************************ CLASS FEATURES ************************* + if(ai_TryBarbarianRageFeat(oCreature)) return; + // ************************* SPELL TALENTS ************************* + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************* SPELL TALENTS ************************* + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ Ranged feat attacks ************************ + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + } + // *************************** Melee feat attacks ************************** + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_bard.nss b/src/module/nss/ai_a_bard.nss new file mode 100644 index 0000000..975bac2 --- /dev/null +++ b/src/module/nss/ai_a_bard.nss @@ -0,0 +1,83 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_bard +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Bard class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryBardSongFeat(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = OBJECT_INVALID; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_cleric.nss b/src/module/nss/ai_a_cleric.nss new file mode 100644 index 0000000..5de1cc2 --- /dev/null +++ b/src/module/nss/ai_a_cleric.nss @@ -0,0 +1,102 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_cleric +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Cleric class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ************************** CLASS FEATURES *************************** + // Turning is basically a powerful AOE so treat it like one. + if(ai_TryTurningTalent(oCreature)) return; + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + } + // SIMPLE+ - Offensive talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = OBJECT_INVALID; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_cntrspell.nss b/src/module/nss/ai_a_cntrspell.nss new file mode 100644 index 0000000..a1bc9ec --- /dev/null +++ b/src/module/nss/ai_a_cntrspell.nss @@ -0,0 +1,69 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_cntrspell +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the combat mode counter spell. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + // We are not in melee combat then we don't attack. + int bAttack = nInMelee; + if(!bAttack) + { + // If there are no casters, i.e. CLERIC or MAGES in the battle then attack. + struct stClasses stClasses = ai_GetFactionsClasses(oCreature); + if(!stClasses.CLERICS && !stClasses.MAGES) bAttack = TRUE; + } + // If we are not attacking and using magic then setup for counter spelling. + if(!bAttack && !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC)) + { + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + if(AI_DEBUG) ai_Debug("ai_a_cntrspell", "30", " Counterspell Mode? " + + IntToString(GetActionMode(OBJECT_SELF, ACTION_MODE_COUNTERSPELL))); + if(!GetActionMode(oCreature, ACTION_MODE_COUNTERSPELL)) + { + object oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER); + // We can only counter spells from a hasted caster if we are hasted as well. + if(ai_GetHasEffectType(oTarget, EFFECT_TYPE_HASTE) && + !ai_GetHasEffectType(oCreature, EFFECT_TYPE_HASTE)) + { + // If we have haste then we should cast it. + if(GetHasSpell(SPELL_HASTE, oCreature)) + { + if(AI_DEBUG) ai_Debug("ai_a_cntrspell", "42", "Opponent is hasted! Casting Haste."); + ActionCastSpellAtObject(SPELL_HASTE, oCreature); + ai_SetLastAction(oCreature, SPELL_HASTE); + return; + } + // If not then we need to go into normal combat. + else + { + if(AI_DEBUG) ai_Debug("ai_cntrspell", "50", "Opponent is hasted! Using ranged AI."); + ExecuteScript("ai_a_ranged"); + return; + } + } + if(oTarget != OBJECT_INVALID) + { + // First a good tactic for counter spelling is to be invisible. + if(ai_TryToBecomeInvisible(oCreature)) return; + // If we have attempted to become invisible or are invisible then + // it is time to counter spell. + if(AI_DEBUG) ai_Debug("ai_a_cntrspell", "61", "Setting Counterspell mode!"); + ActionCounterSpell(oTarget); + return; + } + } + } + if(AI_DEBUG) ai_Debug("ai_a_cntrspell", "67", "Situation is not good for counterspelling! Using ranged AI."); + ExecuteScript("ai_a_ranged"); +} diff --git a/src/module/nss/ai_a_default.nss b/src/module/nss/ai_a_default.nss new file mode 100644 index 0000000..7540340 --- /dev/null +++ b/src/module/nss/ai_a_default.nss @@ -0,0 +1,80 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_no_modes +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to not use any combat modes during combat ai. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy. + 2 - Check for healing and curing first. + 3 - Check moral if wounded and this is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff or summons if this is a difficult+ battle. + 6 - Check for a Class ability and an offensive spell if this is a simple+ battle. + 7 - Check for a physical attack. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + ai_DoPhysicalAttackOnBest(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); +} + diff --git a/src/module/nss/ai_a_defensive.nss b/src/module/nss/ai_a_defensive.nss new file mode 100644 index 0000000..f19523c --- /dev/null +++ b/src/module/nss/ai_a_defensive.nss @@ -0,0 +1,77 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_defensive +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates put in to a defensive mode to protect themselves. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy and the difficulty of the battle. + 2 - Check for healing potions if this is a simple+ battle. + 3 - Check moral if wounded and is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff if this is a difficult+ battle. + 6 - Check for defensive ability such as knockdown, expertise or parry. + 7 - If we can't fight defensive then flee. + 8 - If we are out of range with no ability then stand and watch. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(AI_DEBUG) ai_Debug("ai_a_defensive", "25", "oNearest Enemy: " + GetName(oNearestEnemy) + + " Distance to Nearest Enemy: " + FloatToString(GetDistanceToObject(oNearestEnemy), 0, 2)); + // ALWAYS - Check for healing and cure talents. + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // SIMPLE+ - Check for moral and get what spell power we should be using. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // DIFFICULT+ - Class talents, Offensive AOE's, Defensive talents, and Potion talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS **************** + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if (ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound, oTarget)) return; + } + } + object oTarget; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + if(nInMelee > 0) + { + if(ai_TryImprovedExpertiseFeat(oCreature)) return; + if(ai_TryExpertiseFeat(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = oNearestEnemy; + // Use knockdown when appropriate and the target is not immune. + if(ai_TryKnockdownFeat(oCreature, oTarget)) return; + if (ai_TryParry (oCreature)) return; + // We have tried everything to protect ourselves so the only thing left + // to do is man up and attack! + ai_DoPhysicalAttackOnLowestCR(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + return; + } + //********************** PHYSICAL ATTACKS ******************************** + // Even in defensive mode we want to be in battle so go find someone! + ai_DoPhysicalAttackOnBest(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); +} diff --git a/src/module/nss/ai_a_druid.nss b/src/module/nss/ai_a_druid.nss new file mode 100644 index 0000000..6b82c26 --- /dev/null +++ b/src/module/nss/ai_a_druid.nss @@ -0,0 +1,86 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_druid +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Druid class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // ************************** CLASS FEATURES *************************** + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TryPolymorphSelfFeat(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************** Ranged feat attacks ************************** + object oTarget; + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_fighter.nss b/src/module/nss/ai_a_fighter.nss new file mode 100644 index 0000000..a5f3720 --- /dev/null +++ b/src/module/nss/ai_a_fighter.nss @@ -0,0 +1,82 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: 0i_a_fighter +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Fighter class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = OBJECT_INVALID; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_flanker.nss b/src/module/nss/ai_a_flanker.nss new file mode 100644 index 0000000..fb6845a --- /dev/null +++ b/src/module/nss/ai_a_flanker.nss @@ -0,0 +1,117 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_flanker +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to flank the enemy and not charge into combat. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + oTarget = GetLocalObject(oCreature, AI_PC_LOCKED_TARGET); + // ************************** Melee feat attacks ************************* + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + // Lets get the nearest target that is attacking someone besides me. We want to flank! + if(oTarget == OBJECT_INVALID) + { + if(!nInMelee) oTarget = ai_GetFlankTarget(oCreature); + // If there are few enemies then we can safely move around. + else if(nInMelee < 3 || ai_CanIMoveInCombat(oCreature)) + { + oTarget = ai_GetFlankTarget(oCreature, AI_RANGE_MELEE); + } + // Ok we are in a serious fight so lets not give attack of opportunities. + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + } + // If there are no enemies being attacked then lets stay back. + if(oTarget == OBJECT_INVALID) + { + if(nInMelee) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + object oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + } + // ************************** Ranged feat attacks ************************** + else if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + oTarget = ai_GetLowestCRTarget(oCreature); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + else + { + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + } + if(oTarget != OBJECT_INVALID) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + // Are we too far from our master? + object oMaster = GetMaster(); + if(GetDistanceBetween(oMaster, oCreature) > AI_RANGE_LONG) + { + ActionMoveToObject(oMaster, TRUE, AI_RANGE_CLOSE); + return; + } + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); +} diff --git a/src/module/nss/ai_a_invisible.nss b/src/module/nss/ai_a_invisible.nss new file mode 100644 index 0000000..9772b32 --- /dev/null +++ b/src/module/nss/ai_a_invisible.nss @@ -0,0 +1,123 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_invisible +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to use when they are invisible. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + // Has our master told us to not use magic? + int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_EASY) + { + // *************************** SPELL TALENTS *************************** + if(ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) return; + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound, oTarget)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Melee feat attacks ************************* + // If we won't loose invisibility then ranged attacks are ok! + // ************************ RANGED ATTACKS ******************************* + if(GetHasSpellEffect(SPELL_IMPROVED_INVISIBILITY) || GetHasSpellEffect(SPELLABILITY_AS_IMPROVED_INVISIBLITY)) + { + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + } + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + talent tUse = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_MELEE, 20, oCreature); + if(GetIsTalentValid(tUse)) + { + int nId = GetIdFromTalent(tUse); + if(nId == FEAT_POWER_ATTACK) { if(ai_TryPowerAttackFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_KNOCKDOWN) { if(ai_TryKnockdownFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SMITE_EVIL) { if(ai_TrySmiteEvilFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SMITE_GOOD) { if(ai_TrySmiteGoodFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_IMPROVED_POWER_ATTACK) { if(ai_TryImprovedPowerAttackFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_FLURRY_OF_BLOWS) { if(ai_TryFlurryOfBlowsFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_STUNNING_FIST) { if(ai_TryStunningFistFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SAP) { if(ai_TrySapFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_DISARM) { if(ai_TryDisarmFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_KI_DAMAGE) { if(ai_TryKiDamageFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_CALLED_SHOT) { if(ai_TryCalledShotFeat(oCreature, oTarget)) return; } + } + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} + diff --git a/src/module/nss/ai_a_monk.nss b/src/module/nss/ai_a_monk.nss new file mode 100644 index 0000000..607ce4c --- /dev/null +++ b/src/module/nss/ai_a_monk.nss @@ -0,0 +1,82 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_monk +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Monk class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryWholenessOfBodyFeat(oCreature)) return; + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_no_cmb_mode.nss b/src/module/nss/ai_a_no_cmb_mode.nss new file mode 100644 index 0000000..1ffedb4 --- /dev/null +++ b/src/module/nss/ai_a_no_cmb_mode.nss @@ -0,0 +1,131 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_o_cmb_modes +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to not use any combat modes during combat ai. + OBJECT_SELF is the creature running the ai. + Our actions. + 1 - Get nearest enemy. + 2 - Check for healing and curing first. + 3 - Check moral if wounded and this is a simple+ battle. + 4 - Check for a magical ranged attack if not in melee and a difficult+ battle. + 5 - Check for a buff or summons if this is a difficult+ battle. + 6 - Check for a Class ability and an offensive spell if this is a simple+ battle. + 7 - Check for a physical attack. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + if(AI_DEBUG) ai_Debug("ai_a_no_modes", "78", "Check for ranged attack on weakest enemy!"); + object oTarget; + int bAlwaysAtk = !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK); + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + !ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && + ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the weaker targets. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + if(AI_DEBUG) ai_Debug("ai_a_no_modes", "105", GetName(OBJECT_SELF) + " does ranged attack on weakest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + if(AI_DEBUG) ai_Debug("ai_a_no_modes", "117", "Check for melee attack on weakest enemy!"); + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee, bAlwaysAtk)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, bAlwaysAtk); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee, bAlwaysAtk); + if(oTarget != OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("ai_a_no_modes", "126", GetName(OBJECT_SELF) + " does melee attack against weakest: " + GetName(oTarget) + "!"); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} + diff --git a/src/module/nss/ai_a_paladin.nss b/src/module/nss/ai_a_paladin.nss new file mode 100644 index 0000000..24520a7 --- /dev/null +++ b/src/module/nss/ai_a_paladin.nss @@ -0,0 +1,110 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_paladin +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Paladin class. + Paladins always protect their masters and face the strongest opponents first! + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + } + if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING)) + { + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + // Does our master want to be buffed first? + object oTarget = OBJECT_INVALID; + if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, 0, oTarget)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + } + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + if(ai_TryLayOnHands(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = OBJECT_INVALID; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Paladins ALWAYS protect their masters first! + oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Paladins face off against the strongest opponents first. + if(!nInMelee) oTarget = ai_GetHighestCRTarget(oCreature); + else oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + // Paladins ALWAYS protect their masters first! + oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + int bCheckCombat = ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK); + if(bCheckCombat) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee, FALSE); + // If always attacking Paladins ALWAYS attack the strongest opponent. + else oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_peaceful.nss b/src/module/nss/ai_a_peaceful.nss new file mode 100644 index 0000000..b9bd310 --- /dev/null +++ b/src/module/nss/ai_a_peaceful.nss @@ -0,0 +1,81 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_a_peaceful +//////////////////////////////////////////////////////////////////////////////// + ai script mode for associates to use when they should remain out of combat. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + float fDistance = GetDistanceBetween(oCreature, oNearestEnemy); + // In Melee combat! + if(nInMelee > 0) + { + // If we are not being attacked then we should back out of combat. + if(ai_GetEnemyAttackingMe(oCreature) == OBJECT_INVALID) + { + if(AI_DEBUG) ai_Debug("ai_a_peaceful", "23", GetName(oCreature) + " is moving away from " + GetName(oNearestEnemy) + + "[" + FloatToString(AI_RANGE_MELEE - fDistance + 1.0, 0, 2) + "]" + " to use a ranged weapon."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + // Lets move just out of melee range! + int bRun = ai_CanIMoveInCombat(oCreature); + ActionMoveAwayFromObject(oNearestEnemy, bRun, AI_RANGE_CLOSE + 2.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return; + } + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryImprovedExpertiseFeat(oCreature)) return; + if(ai_TryExpertiseFeat(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + object oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget == OBJECT_INVALID) oTarget = oNearestEnemy; + // Use knockdown when appropriate and the target is not immune. + if(ai_TryKnockdownFeat(oCreature, oTarget)) return; + if (ai_TryParry(oCreature)) return; + // We have tried everything to protect ourselves so the only thing left + // to do is man up and attack! + // Physical attacks are under TALENT_CATEGORY_HARMFUL_MELEE(22). + ai_DoPhysicalAttackOnNearest(oCreature, nInMelee); + return; + } + if(fDistance <= AI_RANGE_LONG) + { + if(AI_DEBUG) ai_Debug("ai_a_peaceful", "49", GetName(oCreature) + " is moving away from " + GetName(oNearestEnemy) + + "[" + FloatToString(AI_RANGE_LONG - fDistance, 0, 2) + "]" + "."); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE); + // Lets move out of close range! + ActionMoveAwayFromObject(oNearestEnemy, TRUE, AI_RANGE_LONG + 2.0); + ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature)); + return; + } + //************************* OUT OF COMBAT ************************** + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, 0, oCreature)) return; + if(ai_TryCureConditionTalent(oCreature, 0)) return; + //************************** DEFENSIVE TALENTS *************************** + // Has our master told us to not use magic? + int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC); + if(bUseMagic) + { + // If can turn invisible then we should probably do that! + if(ai_UseTalent(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY_SPHERE, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_SANCTUARY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_ETHEREALNESS, oCreature)) return; // Greater Sanctuary + if(ai_UseTalent(oCreature, SPELLABILITY_AS_IMPROVED_INVISIBLITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELLABILITY_AS_INVISIBILITY, oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + // Summons are powerfull and should be used as much as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_SUMMON, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_PROTECTION, nInMelee, nMaxLevel)) return; + } + // Stand and watch the battle we don't want to provoke anyone! + if(AI_DEBUG) ai_Debug("ai_a_peaceful", "80", GetName(oCreature) + " is holding here."); +} diff --git a/src/module/nss/ai_a_polymorphed.nss b/src/module/nss/ai_a_polymorphed.nss new file mode 100644 index 0000000..107e6e9 --- /dev/null +++ b/src/module/nss/ai_a_polymorphed.nss @@ -0,0 +1,70 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_polymorphed +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for polymorphed associates. + We check for abilities based on the form we are using and if we should polymorph back. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void ai_DoActions(object oCreature, int nForm) +{ + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(GetPercentageHPLoss(oCreature) <= AI_HEALTH_BLOODY) + { + //ai_Debug("ai_a_polymorphed", "24", "We are wounded and are transforming back!"); + ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH); + return; + } + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // When polymorphed we turn back then check moral. + //if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, FALSE); +} +void main() +{ + object oCreature = OBJECT_SELF; + // Need to know who we are so we can use thier abilities. + int nForm = GetAppearanceType(oCreature); + // Check to see if we are back to our normal form?(-1 to get the actual form #) + if(nForm == GetLocalInt(oCreature, AI_NORMAL_FORM) - 1) + { + // If we are transformed back then go back to our primary ai. + ai_SetCreatureAIScript(oCreature); + DeleteLocalInt(oCreature, AI_NORMAL_FORM); + string sAI = GetLocalString(oCreature, AI_COMBAT_SCRIPT); + if(sAI == "ai_a_polymorphed" || sAI == "") sAI = "ai_a_default"; + ExecuteScript(sAI, oCreature); + } + else ai_DoActions(oCreature, nForm); +} diff --git a/src/module/nss/ai_a_ranged.nss b/src/module/nss/ai_a_ranged.nss new file mode 100644 index 0000000..477937d --- /dev/null +++ b/src/module/nss/ai_a_ranged.nss @@ -0,0 +1,129 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_ranged +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates to use the ranged ai. + OBJECT_SELF is the creature running the ai. + Will attempt to use ranged weapons until surrounded. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + // Turning is basically a powerful AOE so treat it like one. + if(ai_TryTurningTalent(oCreature)) return; + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED)) + { + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + nInMelee < 3) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Lets defend master, nearest favored enemy, ranged, sneak, weakest targets. + if(!nInMelee) + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget == ai_GetRangedTarget(oCreature); + if(oTarget == OBJECT_INVALID && ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + } + // ************************** Melee feat attacks ************************* + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(nInMelee) + { + oTarget = ai_GetEnemyAttackingMe(oCreature); + if(oTarget != OBJECT_INVALID) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + } + } + if(oNearestEnemy != OBJECT_INVALID) + { + float fDistance = GetDistanceBetween(oCreature, oNearestEnemy); + float fRange = AI_RANGE_LONG; + if(GetIsAreaInterior(GetArea(oCreature))) fRange = AI_RANGE_CLOSE; + if(GetHasFeat(FEAT_SNEAK_ATTACK, oCreature)) fRange = AI_RANGE_CLOSE; + if(fDistance < fRange) + { + int bRun = ai_CanIMoveInCombat(oCreature); + ActionMoveAwayFromObject(oNearestEnemy, bRun, fRange - fDistance + 2.0); + } + } + else ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); +} + diff --git a/src/module/nss/ai_a_ranger.nss b/src/module/nss/ai_a_ranger.nss new file mode 100644 index 0000000..179298f --- /dev/null +++ b/src/module/nss/ai_a_ranger.nss @@ -0,0 +1,96 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_ranger +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Ranger class. + Rangers will take out favored enemies first! + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) + { + oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature); + } + else + { + oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + // Our master may have setup to check difficulty before we move into melee. + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_PERCEPTION, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_rogue.nss b/src/module/nss/ai_a_rogue.nss new file mode 100644 index 0000000..10e1ae0 --- /dev/null +++ b/src/module/nss/ai_a_rogue.nss @@ -0,0 +1,83 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_rogue +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Rogue class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_sorcerer.nss b/src/module/nss/ai_a_sorcerer.nss new file mode 100644 index 0000000..5e4a3b7 --- /dev/null +++ b/src/module/nss/ai_a_sorcerer.nss @@ -0,0 +1,75 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_sorcerer +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Sorcerer class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_a_taunter.nss b/src/module/nss/ai_a_taunter.nss new file mode 100644 index 0000000..b06fed8 --- /dev/null +++ b/src/module/nss/ai_a_taunter.nss @@ -0,0 +1,53 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_a_taunter +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using defined to use the taunt skill. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Class and Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + // ************************** CLASS FEATURES *************************** + if(ai_TryTurningTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // Taunt the nearest target! + if (ai_TryTaunt (oCreature, ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee))) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + ai_DoPhysicalAttackOnLowestCR(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); +} diff --git a/src/module/nss/ai_a_wizard.nss b/src/module/nss/ai_a_wizard.nss new file mode 100644 index 0000000..dfad8c3 --- /dev/null +++ b/src/module/nss/ai_a_wizard.nss @@ -0,0 +1,77 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_a_wizard +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for associates using the Wizard class. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + int nDifficulty = ai_GetDifficulty(oCreature); + int nMaxLevel; + // Check for moral and get the maximum spell level we should use. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(nInMelee && ai_MoralCheck(oCreature)) return; + nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty); + } + // Skill, Class, Offensive AOE's, and Defensive talents. + if(nDifficulty >= AI_COMBAT_MODERATE) + { + // ************************** CLASS FEATURES *************************** + if(ai_TrySummonFamiliarTalent(oCreature)) return; + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + } + // Offensive single target talents. + if(nDifficulty >= AI_COMBAT_EFFORTLESS) + { + if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING)) + { + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + } + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Are we suppose to protect our master first? + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) + { + // Lets pick off the weakest targets. + if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature); + else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetBestTargetForMeleeCombat(oCreature, nInMelee, !ai_GetAIMode(oCreature, AI_MODE_CHECK_ATTACK)); + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, FALSE); +} diff --git a/src/module/nss/ai_ambusher.nss b/src/module/nss/ai_ambusher.nss new file mode 100644 index 0000000..829a3da --- /dev/null +++ b/src/module/nss/ai_ambusher.nss @@ -0,0 +1,100 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_ambusher +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for ambushing creatures (Any). + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + // Rule used to disable ambush if the player wants to. + if(!GetLocalInt(GetModule(), AI_RULE_AMBUSH)) + { + ExecuteScript("ai_default", oCreature); + return; + } + // If can turn invisible then we should probably do that! + if(ai_UseTalent(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY_SPHERE, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_SANCTUARY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_ETHEREALNESS, oCreature)) return; // Greater Sanctuary + if(ai_UseTalent(oCreature, SPELLABILITY_AS_IMPROVED_INVISIBLITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELLABILITY_AS_INVISIBILITY, oCreature)) return; + // Check the battle field to see if anyone see us? + int nEnemyIndex = ai_GetNearestIndexThatSeesUs(oCreature); + // If seen, can we try to hide now? + if(nEnemyIndex) + { + // Check for an attacker and can they see through invisibility? + object oAttacker = ai_GetEnemyAttackingMe(oCreature); + int bCanSeeInvisible; + if(oAttacker != OBJECT_INVALID) + { + bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_SEEINVISIBLE); + if(!bCanSeeInvisible) bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_TRUESEEING); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_5_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_10_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_60_FEET, oCreature); + } + if(AI_DEBUG) ai_Debug("ai_ambusher", "43", "bCanSeeInvisible: " + IntToString(bCanSeeInvisible)); + if(!bCanSeeInvisible) + { + if(GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oCreature)) + { + if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + if(AI_DEBUG) ai_Debug("ai_ambusher", "50", GetName(oCreature) + " is using hide in plain sight!"); + ClearAllActions(TRUE); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + return; + } + } + // Does not have hide in plain sight. + else + { + string sEnemyIndex = IntToString(nEnemyIndex); + float fEnemyDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + sEnemyIndex); + if(AI_DEBUG) ai_Debug("ai_ambusher", "61", "fDistance: " + FloatToString(fEnemyDistance, 0, 2)); + if(fEnemyDistance >= AI_RANGE_LONG) + { + int bTried = GetLocalInt(oCreature, AI_TRIED_TO_HIDE); + if(!bTried) + { + // Move away so we can hide. + if(AI_DEBUG) ai_Debug("ai_ambusher", "68", GetName(oCreature) + " is trying to move away to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + object oEnemy = GetLocalObject(oCreature, AI_ENEMY + sEnemyIndex); + ActionMoveAwayFromObject(oEnemy, TRUE, AI_RANGE_BATTLEFIELD); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + else SetLocalInt(oCreature, AI_TRIED_TO_HIDE, GetLocalInt(oCreature, AI_TRIED_TO_HIDE) - 1); + } + // We have been seen by an enemy too close to us so drop stealth. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + } + // The enemy can see through stealth so lets drop it. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + // We are not in stealth mode so lets get there. + else if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + // Use any hiding talents we have + if(AI_DEBUG) ai_Debug("ai_ambusher", "88", GetName(oCreature) + " is trying to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + // If we have givin up on stealth do our normal actions. + string sScript = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + if(sScript == "ai_ambusher" || sScript == "") sScript = "ai_default"; + if(AI_DEBUG) ai_Debug("ai_ambusher", "96", "sScript: " + sScript + " AI_DEFAULT_SCRIPT: " + GetLocalString(oCreature, AI_DEFAULT_SCRIPT)); + ExecuteScript(sScript, oCreature); +} diff --git a/src/module/nss/ai_barbarian.nss b/src/module/nss/ai_barbarian.nss new file mode 100644 index 0000000..69efcb4 --- /dev/null +++ b/src/module/nss/ai_barbarian.nss @@ -0,0 +1,71 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_barbarian +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Barbarian. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oTarget; + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature)) + { + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // *************************** RANGED ATTACKS ***************************** + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + } + // ***************************** MELEE ATTACKS *************************** + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_bard.nss b/src/module/nss/ai_bard.nss new file mode 100644 index 0000000..9dde198 --- /dev/null +++ b/src/module/nss/ai_bard.nss @@ -0,0 +1,67 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_bard +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Bard. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBardSongFeat(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_cleric.nss b/src/module/nss/ai_cleric.nss new file mode 100644 index 0000000..34bd1e6 --- /dev/null +++ b/src/module/nss/ai_cleric.nss @@ -0,0 +1,68 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_cleric +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Cleric. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryTurningTalent(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_cntrspell.nss b/src/module/nss/ai_cntrspell.nss new file mode 100644 index 0000000..04939c9 --- /dev/null +++ b/src/module/nss/ai_cntrspell.nss @@ -0,0 +1,68 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_cntrspell +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the combat mode counter spell. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + // We are not in melee combat then we don't attack. + int bAttack = nInMelee; + if(!bAttack) + { + // If there are no casters, i.e. CLERIC or MAGES in the battle then attack. + struct stClasses stClasses = ai_GetFactionsClasses(oCreature); + if(!stClasses.CLERICS && !stClasses.MAGES) bAttack = TRUE; + } + // If we are not attacking then setup for counter spelling. + if(!bAttack) + { + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(AI_DEBUG) ai_Debug("ai_cntrspell", "29", " Counterspell Mode? " + + IntToString(GetActionMode(OBJECT_SELF, ACTION_MODE_COUNTERSPELL))); + if(!GetActionMode(oCreature, ACTION_MODE_COUNTERSPELL)) + { + object oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER); + // We can only counter spells from a hasted caster if we are hasted as well. + if(ai_GetHasEffectType(oTarget, EFFECT_TYPE_HASTE) && + !ai_GetHasEffectType(oCreature, EFFECT_TYPE_HASTE)) + { + // If we have haste then we should cast it. + if(GetHasSpell(SPELL_HASTE, oCreature)) + { + if(AI_DEBUG) ai_Debug("ai_cntrspell", "41", "Opponent is hasted! Casting Haste."); + ActionCastSpellAtObject(SPELL_HASTE, oCreature); + ai_SetLastAction(oCreature, SPELL_HASTE); + return; + } + // If not then we need to go into normal combat. + else + { + if(AI_DEBUG) ai_Debug("ai_cntrspell", "49", "Opponent is hasted! Using ranged AI."); + ExecuteScript("ai_ranged"); + return; + } + } + if(oTarget != OBJECT_INVALID) + { + // First a good tactic for counter spelling is to be invisible. + if(ai_TryToBecomeInvisible(oCreature)) return; + // If we have attempted to become invisible or are invisible then + // it is time to counter spell. + if(AI_DEBUG) ai_Debug("ai_cntrspell", "60", "Setting Counterspell mode!"); + ActionCounterSpell(oTarget); + return; + } + } + } + if(AI_DEBUG) ai_Debug("ai_cntrspell", "66", "Situation is not good for counterspelling! Using ranged AI."); + ExecuteScript("ai_ranged"); +} diff --git a/src/module/nss/ai_coward.nss b/src/module/nss/ai_coward.nss new file mode 100644 index 0000000..b88e424 --- /dev/null +++ b/src/module/nss/ai_coward.nss @@ -0,0 +1,133 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_coward +//////////////////////////////////////////////////////////////////////////////// + ai script for cowardly creatures (Any) used when they fail a moral check or + when associates are to remain out of combat. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with us. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + // If we have been healed up then get back in there! + if(ai_GetPercHPLoss(oCreature) > AI_HEALTH_WOUNDED) + { + string sDefaultCombatScript = GetLocalString(oCreature, AI_DEFAULT_SCRIPT); + SetLocalString(oCreature, AI_COMBAT_SCRIPT, sDefaultCombatScript); + ExecuteScript(sDefaultCombatScript, oCreature); + return; + } + // In Melee combat! + if(nInMelee) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryImprovedExpertiseFeat(oCreature)) return; + if(ai_TryExpertiseFeat(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + object oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget == OBJECT_INVALID) oTarget = oNearestEnemy; + // Use knockdown when appropriate and the target is not immune. + if(ai_TryKnockdownFeat(oCreature, oTarget)) return; + if (ai_TryParry(oCreature)) return; + // We have tried everything to protect ourselves so the only thing left + // to do is man up and attack! + // Physical attacks are under TALENT_CATEGORY_HARMFUL_MELEE(22). + ai_DoPhysicalAttackOnNearest(oCreature, nInMelee); + return; + } + else + { + // If can turn invisible then we should probably do that! + if(ai_UseTalent(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_INVISIBILITY_SPHERE, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_SANCTUARY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELL_ETHEREALNESS, oCreature)) return; // Greater Sanctuary + if(ai_UseTalent(oCreature, SPELLABILITY_AS_IMPROVED_INVISIBLITY, oCreature)) return; + if(ai_UseTalent(oCreature, SPELLABILITY_AS_INVISIBILITY, oCreature)) return; + // If we are seen by the enemy we need to move back so we can hide. + int nEnemyIndex = ai_GetNearestIndexThatSeesUs(oCreature); + if(nEnemyIndex) + { + // Check for an attacker and can they see through invisibility? + object oAttacker = ai_GetEnemyAttackingMe(oCreature); + int bCanSeeInvisible; + if(oAttacker != OBJECT_INVALID) + { + bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_SEEINVISIBLE); + if(!bCanSeeInvisible) bCanSeeInvisible = ai_GetHasEffectType(oAttacker, EFFECT_TYPE_TRUESEEING); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_5_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_10_FEET, oCreature); + if(!bCanSeeInvisible) bCanSeeInvisible = GetHasFeat(FEAT_BLINDSIGHT_60_FEET, oCreature); + } + if(!bCanSeeInvisible) + { + if(GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oCreature)) + { + if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + if(AI_DEBUG) ai_Debug("ai_coward", "74", GetName(oCreature) + " is using hide in plain sight!"); + ClearAllActions(TRUE); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + return; + } + } + // Does not have hide in plain sight. + else + { + string sEnemyIndex = IntToString(nEnemyIndex); + float fEnemyDistance = GetLocalFloat(oCreature, AI_ENEMY_RANGE + sEnemyIndex); + if(AI_DEBUG) ai_Debug("ai_coward", "85", "fDistance: " + FloatToString(fEnemyDistance, 0, 2)); + if(fEnemyDistance >= AI_RANGE_CLOSE) + { + int bTried = GetLocalInt(oCreature, AI_TRIED_TO_HIDE); + if(!bTried) + { + // Move away so we can hide. + if(AI_DEBUG) ai_Debug("ai_coward", "93", GetName(oCreature) + " is trying to move away to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + object oEnemy = GetLocalObject(oCreature, AI_ENEMY + sEnemyIndex); + ActionMoveAwayFromObject(oEnemy, TRUE, AI_RANGE_BATTLEFIELD); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + else SetLocalInt(oCreature, AI_TRIED_TO_HIDE, GetLocalInt(oCreature, AI_TRIED_TO_HIDE) - 1); + } + // We have been seen by an enemy near us so drop stealth. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + } + // The enemy can see through stealth so lets drop it. + else SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + } + // We are not in stealth mode so lets get there. + else if(!GetActionMode(oCreature, ACTION_MODE_STEALTH)) + { + // Use any hiding talents we have + if(AI_DEBUG) ai_Debug("ai_coward", "113", GetName(oCreature) + " is trying to hide!"); + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + SetLocalInt(oCreature, AI_TRIED_TO_HIDE, 3); + return; + } + } + // Either we cannot go into stealth or we are in stealth so do something else. + //************************* OUT OF MELEE COMBAT ************************** + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, 0, oCreature)) return; + if(ai_TryCureConditionTalent(oCreature, 0)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //************************** DEFENSIVE TALENTS *************************** + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel)) return; + // Stand and watch the battle we don't want to provoke anyone! + if(AI_DEBUG) ai_Debug("ai_coward", "132", GetName(oCreature) + " is holding here."); +} diff --git a/src/module/nss/ai_default.nss b/src/module/nss/ai_default.nss new file mode 100644 index 0000000..cfe8e8f --- /dev/null +++ b/src/module/nss/ai_default.nss @@ -0,0 +1,49 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_default +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for default creatures(Any). + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + if(ai_TryPolymorphSelfFeat(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + ai_DoPhysicalAttackOnNearest(oCreature, nInMelee); +} diff --git a/src/module/nss/ai_defensive.nss b/src/module/nss/ai_defensive.nss new file mode 100644 index 0000000..15f5275 --- /dev/null +++ b/src/module/nss/ai_defensive.nss @@ -0,0 +1,48 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_defensive +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures put in to a defensive mode to protect themselves(Any). + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + //************************** DEFENSIVE TALENTS *************************** + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel)) return; + //******************** DEFENSIVE MELEE FEATS ***************************** + if(nInMelee > 0) + { + if(ai_TryImprovedExpertiseFeat(oCreature)) return; + if(ai_TryExpertiseFeat(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + object oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget == OBJECT_INVALID) oTarget = oNearestEnemy; + // Use knockdown when appropriate and the target is not immune + if(ai_TryKnockdownFeat(oCreature, oTarget)) return; + if(ai_TryParry(oCreature)) return; + } + //********************** PHYSICAL ATTACKS ******************************** + // Even in defensive mode we want to be in battle so go find someone! + ai_DoPhysicalAttackOnNearest(oCreature, nInMelee); +} diff --git a/src/module/nss/ai_dragon.nss b/src/module/nss/ai_dragon.nss new file mode 100644 index 0000000..a82362c --- /dev/null +++ b/src/module/nss/ai_dragon.nss @@ -0,0 +1,51 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_dragon +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for dragons. + OBJECT_SELF is the dragons running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + // Dragons do not flee! if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // ************************ MELEE ATTACKS ******************************** + object oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(GetDistanceBetween(oCreature, oTarget) > AI_RANGE_CLOSE) + { + // Can we do a crush attack(HD 18+)? + if(ai_TryCrushAttack(oCreature, oTarget)) return; + ai_FlyToTarget(oCreature, oTarget); + return; + } + if(ai_TryDragonBreathAttack(oCreature, nRound)) return; + ai_TryWingAttacks(oCreature); + // If we don't do a Tail sweep attack(HD 30+) then see if we can do a Tail slap(HD 12+)! + if(!ai_TryTailSweepAttack(oCreature)) ai_TryTailSlap(oCreature); + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_druid.nss b/src/module/nss/ai_druid.nss new file mode 100644 index 0000000..95cb82b --- /dev/null +++ b/src/module/nss/ai_druid.nss @@ -0,0 +1,70 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_druid +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Druid. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS) && ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TryPolymorphSelfFeat(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // All else fails lets see if we have any good potions. + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Lets pick off the nearest targets. + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_fighter.nss b/src/module/nss/ai_fighter.nss new file mode 100644 index 0000000..04f4ce0 --- /dev/null +++ b/src/module/nss/ai_fighter.nss @@ -0,0 +1,65 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_fighter +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Fighter. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange (oCreature); + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //***************** OFFENSIVE AREA OF EFFECT TALENTS ********************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + // *********************** DEFENSIVE TALENTS ***************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //******************* OFFENSIVE TARGETED TALENTS ************************* + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // *************************** RANGED ATTACKS **************************** + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // **************************** MELEE ATTACKS **************************** + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryWhirlwindFeat (oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee); + if (oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents (oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_flanker.nss b/src/module/nss/ai_flanker.nss new file mode 100644 index 0000000..20a6538 --- /dev/null +++ b/src/module/nss/ai_flanker.nss @@ -0,0 +1,102 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_flanker +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for monsters to flank the enemy and not charge into combat. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //***************** OFFENSIVE AREA OF EFFECT TALENTS ********************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + // *********************** DEFENSIVE TALENTS ***************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //******************* OFFENSIVE TARGETED TALENTS ************************* + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Melee feat attacks ************************* + // Lets get the nearest target that is attacking someone besides me. We want to flank! + if(oTarget == OBJECT_INVALID) + { + if(!nInMelee) oTarget = ai_GetFlankTarget(oCreature); + // If there are few enemies then we can safely move around. + else if(nInMelee < 3 || ai_CanIMoveInCombat(oCreature)) + { + oTarget = ai_GetFlankTarget(oCreature, AI_RANGE_MELEE); + } + // Ok we are in a serious fight so lets not give attack of opportunities. + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + } + // If there are no enemies being attacked then lets stay back. + if(oTarget == OBJECT_INVALID) + { + if(nInMelee) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + // Lets get the strongest melee opponent in melee with us. + object oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + } + // ************************** Ranged feat attacks ************************** + if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + oTarget = ai_GetNearestTarget(oCreature); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + else + { + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + } + if(oTarget != OBJECT_INVALID) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); +} diff --git a/src/module/nss/ai_incorporeal.nss b/src/module/nss/ai_incorporeal.nss new file mode 100644 index 0000000..cdd20bd --- /dev/null +++ b/src/module/nss/ai_incorporeal.nss @@ -0,0 +1,83 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_incorporeal +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures that are incorporeal. + oCreature is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange (oCreature); + if (nInMelee && ai_MoralCheck (oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if (!GetHasFeatEffect (FEAT_BARBARIAN_RAGE, oCreature) && ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if (ai_TryRangedSneakAttack (oCreature, nInMelee)) return; + string sIndex; + if (!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat (oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee); + if (oTarget != OBJECT_INVALID) + { + // If we are using our hands then do a touch attack instead. + if (GetItemInSlot (INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID) + { + if (GetItemInSlot (INVENTORY_SLOT_CWEAPON_L) != OBJECT_INVALID) + { + // Randomize so they don't appear synchronized. + float fDelay = IntToFloat(Random(2) + 1); + DelayCommand(fDelay, ActionCastSpellAtObject (769/*Shadow_Attack*/, oTarget, METAMAGIC_ANY, TRUE)); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MELEE_ATK); + SetLocalObject (oCreature, AI_ATTACKED_PHYSICAL, oTarget); + } + } + else ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_invisible.nss b/src/module/nss/ai_invisible.nss new file mode 100644 index 0000000..7d42b21 --- /dev/null +++ b/src/module/nss/ai_invisible.nss @@ -0,0 +1,93 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_invisible +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures(Any) that are invisible. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + // Skill, Class, Offensive AOE's, and Defensive talents. + // *************************** SPELL TALENTS *************************** + // ********** PROTECTION/ENHANCEMENT/SUMMON TALENTS ************ + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + // ************************** CLASS FEATURES *************************** + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + // ******************* OFFENSIVE AOE TALENTS *********************** + // Check the battlefield for a group of enemies to shoot a big spell at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // If we won't loose invisibility then ranged attacks are ok! + // ************************ RANGED ATTACKS ******************************* + if(GetHasSpellEffect(SPELL_IMPROVED_INVISIBILITY) || GetHasSpellEffect(SPELLABILITY_AS_IMPROVED_INVISIBLITY)) + { + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + talent tUse = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_MELEE, 20, oCreature); + if(GetIsTalentValid(tUse)) + { + int nId = GetIdFromTalent(tUse); + if(nId == FEAT_POWER_ATTACK) { if(ai_TryPowerAttackFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_KNOCKDOWN) { if(ai_TryKnockdownFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SMITE_EVIL) { if(ai_TrySmiteEvilFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SMITE_GOOD) { if(ai_TrySmiteGoodFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_IMPROVED_POWER_ATTACK) { if(ai_TryImprovedPowerAttackFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_FLURRY_OF_BLOWS) { if(ai_TryFlurryOfBlowsFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_STUNNING_FIST) { if(ai_TryStunningFistFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_SAP) { if(ai_TrySapFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_DISARM) { if(ai_TryDisarmFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_KI_DAMAGE) { if(ai_TryKiDamageFeat(oCreature, oTarget)) return; } + else if(nId == FEAT_CALLED_SHOT) { if(ai_TryCalledShotFeat(oCreature, oTarget)) return; } + } + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_monk.nss b/src/module/nss/ai_monk.nss new file mode 100644 index 0000000..d6ff1b6 --- /dev/null +++ b/src/module/nss/ai_monk.nss @@ -0,0 +1,65 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_monk +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Monk. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange (oCreature); + //*************************** HEALING & CURES **************************** + if (ai_TryWholenessOfBodyFeat (oCreature)) return; + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck (oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if (!nInMelee) oTarget = ai_GetNearestTarget (oCreature); + else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee); + if (oTarget != OBJECT_INVALID) + { + if (ai_TryMeleeTalents (oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_paladin.nss b/src/module/nss/ai_paladin.nss new file mode 100644 index 0000000..d45d223 --- /dev/null +++ b/src/module/nss/ai_paladin.nss @@ -0,0 +1,71 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_paladin +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Paladin. + Paladins face the strongest opponents on the battlefield first! + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryTurningTalent(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + if(ai_TryDivineShieldFeat(oCreature, nInMelee)) return; + if(ai_TryDivineMightFeat(oCreature, nInMelee)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Paladins face the biggest challenges first! + if(!nInMelee) oTarget = ai_GetHighestCRTarget(oCreature); + else oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + // Paladins face the biggest challenges first! + oTarget = ai_GetHighestCRTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_polymorphed.nss b/src/module/nss/ai_polymorphed.nss new file mode 100644 index 0000000..9a7630a --- /dev/null +++ b/src/module/nss/ai_polymorphed.nss @@ -0,0 +1,55 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_polymorphed +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for polymorphed creatures. + We check for abilities based on the form we are using and if we should polymorph back. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void ai_DoActions(object oCreature, int nForm) +{ + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(GetPercentageHPLoss(oCreature) <= AI_HEALTH_BLOODY) + { + if(AI_DEBUG) ai_Debug("ai_polymorphed", "19", "We are wounded and are transforming back!"); + ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH); + return; + } + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + // When polymorphed we turn back then check moral. + // if(nInMelee && ai_MoralCheck(oCreature)) return; + // Skill, Class, Offensive AOE's, and Defensive talents. + // *************************** SPELL TALENTS *************************** + if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return; + // Class and Offensive single target talents. + // *************************** SPELL TALENTS *************************** + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + // If we don't find a target then we don't want to fight anyone! + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, TRUE); +} +void main() +{ + object oCreature = OBJECT_SELF; + // Need to know who we are so we can use thier abilities. + int nForm = GetAppearanceType(oCreature); + // Check to see if we are back to our normal form?(-1 to get the actual form #) + if(nForm == GetLocalInt(oCreature, AI_NORMAL_FORM) - 1) + { + // If we are transformed back then go back to our primary ai. + ai_SetCreatureAIScript(oCreature); + DeleteLocalInt(oCreature, AI_NORMAL_FORM); + string sAI = GetLocalString(oCreature, AI_COMBAT_SCRIPT); + if(sAI == "ai_polymorphed" || sAI == "") sAI = "ai_default"; + ExecuteScript(sAI, oCreature); + } + else ai_DoActions(oCreature, nForm); +} diff --git a/src/module/nss/ai_ranged.nss b/src/module/nss/ai_ranged.nss new file mode 100644 index 0000000..3a46228 --- /dev/null +++ b/src/module/nss/ai_ranged.nss @@ -0,0 +1,116 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_ranged +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for monsters to use the ranged ai. + OBJECT_SELF is the creature running the ai. + Will attempt to use ranged weapons/spells until surrounded. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + // Check for moral and get the maximum spell level we should use. + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + // ************************** CLASS FEATURES ******************************* + if(ai_TryTurningTalent(oCreature)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + object oTarget; + // ************************** Ranged feat attacks ************************** + if(!GetHasFeatEffect(FEAT_BARBARIAN_RAGE, oCreature) && + (nInMelee < 3 || ai_GetEnemyAttackingMe(oCreature) == OBJECT_INVALID)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + // Lets pick off the ranged then nearest targets. + if(!nInMelee) + { + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget == ai_GetRangedTarget(oCreature); + if(oTarget == OBJECT_INVALID && ai_TryRangedSneakAttack(oCreature, nInMelee)) return; + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature); + } + else + { + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************** Melee feat attacks ************************* + object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST); + if(nInMelee) + { + oTarget = ai_GetEnemyAttackingMe(oCreature); + if(oTarget != OBJECT_INVALID) + { + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if(ai_TrySneakAttack(oCreature, nInMelee)) return; + if(ai_TryWhirlwindFeat(oCreature)) return; + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + return; + } + } + } + if(oNearestEnemy != OBJECT_INVALID) + { + float fDistance = GetDistanceBetween(oCreature, oNearestEnemy); + float fRange = AI_RANGE_LONG; + if(GetHasFeat(FEAT_SNEAK_ATTACK, oCreature)) fRange = AI_RANGE_CLOSE; + if(fDistance < fRange) + { + int bRun = ai_CanIMoveInCombat(oCreature); + ActionMoveAwayFromObject(oNearestEnemy, bRun, fRange - fDistance + 2.0); + } + } + else ai_SearchForHiddenCreature(oCreature, FALSE, OBJECT_INVALID, AI_RANGE_CLOSE); +} + diff --git a/src/module/nss/ai_ranger.nss b/src/module/nss/ai_ranger.nss new file mode 100644 index 0000000..5878cfb --- /dev/null +++ b/src/module/nss/ai_ranger.nss @@ -0,0 +1,79 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_ranger +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Ranger. + Need to add ---> Rangers will take out favored enemies first! + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS) && ai_TrySummonAnimalCompanionTalent(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) + { + oTarget = ai_GetNearestFavoredEnemyTarget(oCreature); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature); + } + else + { + oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + } + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE); + if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryMeleeTalents(oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_rogue.nss b/src/module/nss/ai_rogue.nss new file mode 100644 index 0000000..81c4500 --- /dev/null +++ b/src/module/nss/ai_rogue.nss @@ -0,0 +1,66 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_rogue +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Rogue. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange (oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck (oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if (ai_TryRangedSneakAttack (oCreature, nInMelee)) return; + oTarget = ai_GetNearestTarget (oCreature); + if(oTarget != OBJECT_INVALID) + { + if (ai_TryRapidShotFeat (oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + if (ai_TrySneakAttack (oCreature, nInMelee)) return; + oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee); + if (oTarget != OBJECT_INVALID) + { + if (ai_TryMeleeTalents (oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_shadow.nss b/src/module/nss/ai_shadow.nss new file mode 100644 index 0000000..3d6419f --- /dev/null +++ b/src/module/nss/ai_shadow.nss @@ -0,0 +1,77 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_shadow +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures that are incorporeal. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + // Shadows do not flee! if(nInMelee && ai_MoralCheck()) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************ RANGED ATTACKS ******************************* + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + string sIndex; + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee); + if(oTarget != OBJECT_INVALID) + { + // If we are using our hands then do a touch attack instead. + if(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID) + { + if(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L) != OBJECT_INVALID) + { + // Randomize so they don't appear synchronized. + float fDelay = IntToFloat(Random(2) + 1); + DelayCommand(fDelay, ActionCastSpellAtObject (769/*Shadow_Attack*/, oTarget, METAMAGIC_ANY, TRUE)); + ai_SetLastAction(oCreature, AI_LAST_ACTION_MELEE_ATK); + SetLocalObject (oCreature, AI_ATTACKED_PHYSICAL, oTarget); + } + } + else ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_sorcerer.nss b/src/module/nss/ai_sorcerer.nss new file mode 100644 index 0000000..f1fdcc3 --- /dev/null +++ b/src/module/nss/ai_sorcerer.nss @@ -0,0 +1,61 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_sorcerer +////////////////////////////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Sorcerer. + OBJECT_SELF is the creature running the ai. +*///////////////////////////////////////////////////////////////////////////////////////////////////// +// Programmer: Philos +////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************* OFFENSIVE TARGETED TALENTS *********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************** RANGED ATTACKS ***************************** + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee, FALSE); + // I have a target now lets see if we want to move in! + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, TRUE, OBJECT_INVALID, AI_RANGE_CLOSE); +} diff --git a/src/module/nss/ai_taunter.nss b/src/module/nss/ai_taunter.nss new file mode 100644 index 0000000..825d025 --- /dev/null +++ b/src/module/nss/ai_taunter.nss @@ -0,0 +1,78 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: ai_taunter +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using defined to use the taunt skill. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange (oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck (oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + //**************************** CLASS FEATURES **************************** + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) return; + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS)) + { + if(ai_TrySummonFamiliarTalent(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + } + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************** OFFENSIVE TARGETED TALENTS ********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // *************************** RANGED ATTACKS ***************************** + // We use a bow when we are not in melee, or only 1 enemy with PBS. + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if (!nInMelee) oTarget = ai_GetNearestTarget (oCreature); + else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ***************************** MELEE ATTACKS *************************** + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee); + if (oTarget != OBJECT_INVALID) + { + if (ai_TryTaunt (oCreature, oTarget)) return; + if (ai_TryMeleeTalents (oCreature, oTarget)) return; + ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + } + else ai_SearchForHiddenCreature(oCreature, TRUE); +} diff --git a/src/module/nss/ai_wizard.nss b/src/module/nss/ai_wizard.nss new file mode 100644 index 0000000..6baa4c8 --- /dev/null +++ b/src/module/nss/ai_wizard.nss @@ -0,0 +1,63 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: ai_wizard +//////////////////////////////////////////////////////////////////////////////// + ai script for creatures using the class Wizard. + OBJECT_SELF is the creature running the ai. +//////////////////////////////////////////////////////////////////////////////// + Programmer: Philos +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +void main() +{ + object oCreature = OBJECT_SELF; + // Get the number of enemies that we are in melee combat with. + int nInMelee = ai_GetNumOfEnemiesInRange(oCreature); + //*************************** HEALING & CURES **************************** + if(ai_TryHealingTalent(oCreature, nInMelee)) return; + if(ai_TryCureConditionTalent(oCreature, nInMelee)) return; + if(nInMelee && ai_MoralCheck(oCreature)) return; + int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature); + //******************* OFFENSIVE AREA OF EFFECT TALENTS ******************* + // Check the battlefield for a group of enemies to shoot a big talent at! + // We are checking here since these opportunities are rare and we need + // to take advantage of them as often as possible. + if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return; + // ************************** CLASS FEATURES **************************** + if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS) && ai_TrySummonFamiliarTalent(oCreature)) return; + //************************** DEFENSIVE TALENTS *************************** + int nRound = ai_GetCurrentRound(oCreature); + if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return; + //********************* OFFENSIVE TARGETED TALENTS *********************** + // Look for a touch attack since we are in melee. + if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return; + if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return; + // PHYSICAL ATTACKS - Either we don't have talents or we are saving them. + // ************************** RANGED ATTACKS ***************************** + object oTarget; + if(ai_CanIUseRangedWeapon(oCreature, nInMelee)) + { + if(ai_HasRangedWeaponWithAmmo(oCreature)) + { + if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature); + else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE); + if(oTarget != OBJECT_INVALID) + { + ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE); + return; + } + else + { + ai_SearchForHiddenCreature(oCreature, TRUE, OBJECT_INVALID, AI_RANGE_CLOSE); + return; + } + } + else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return; + } + // ************************* MELEE ATTACKS ******************************* + if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return; + oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee, TRUE); + // I have a target now lets see if we want to move in! + if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget); + else ai_SearchForHiddenCreature(oCreature, TRUE, OBJECT_INVALID, AI_RANGE_CLOSE); +} diff --git a/src/module/nss/dmfi_db_biow_inc.nss b/src/module/nss/dmfi_db_biow_inc.nss index d098de8..40d00fc 100644 --- a/src/module/nss/dmfi_db_biow_inc.nss +++ b/src/module/nss/dmfi_db_biow_inc.nss @@ -15,7 +15,7 @@ //:: for Knat's NBDE -const int DMFI_DB_TYPE =DMFI_DB_TYPE_BIOWARE; +const int DMFI_DB_TYPE =1; void FlushDMFIPersistentData(string sDBName) { diff --git a/src/module/nss/dmfi_db_nbde_inc.nss b/src/module/nss/dmfi_db_nbde_inc.nss index 938ab7d..1cd48e8 100644 --- a/src/module/nss/dmfi_db_nbde_inc.nss +++ b/src/module/nss/dmfi_db_nbde_inc.nss @@ -9,7 +9,7 @@ //:: for Knat's NBDE -const int DMFI_DB_TYPE = DMFI_DB_TYPE_NBDE; +const int DMFI_DB_TYPE = 2; #include "nbde_inc" diff --git a/src/module/nss/hif_onenter.nss b/src/module/nss/hif_onenter.nss new file mode 100644 index 0000000..2b168ff --- /dev/null +++ b/src/module/nss/hif_onenter.nss @@ -0,0 +1,14 @@ +void main() +{ + + object oPC = GetEnteringObject(); + + ExecuteScript("prc_onenter", oPC); + + AddJournalQuestEntry("JRNL_XPCHART", 1, oPC, FALSE, FALSE, FALSE); + AddJournalQuestEntry("JRNL_LA_BUYOFF", 1, oPC, FALSE, FALSE, FALSE); + AddJournalQuestEntry("JRNL_PRC8", 1, oPC, FALSE, FALSE, FALSE); + + ExecuteScript("0e_onclientload", oPC); + +} \ No newline at end of file diff --git a/src/module/nss/loot_inc_main.nss b/src/module/nss/loot_inc_main.nss index a2466ba..74bad8d 100644 --- a/src/module/nss/loot_inc_main.nss +++ b/src/module/nss/loot_inc_main.nss @@ -1,5 +1,7 @@ // Throw this switch for debugging +#include "loot_inc_data" + int LOOT_INC_MAIN_DEBUGGING = TRUE; @@ -16,7 +18,7 @@ while (GetIsObjectValid (oPartyMember)) iPartyMemberLevel = GetLevelByPosition (1, oPartyMember) + GetLevelByPosition (2, oPartyMember) + GetLevelByPosition (3, oPartyMember); if (iPartyMemberLevel < iMinimumLevel) iPartyMemberCount --; } - oPartyMember = GetNextFactionMember (oPC); + oPartyMember = GetNextFactionMember(oPC); } if (iPartyMemberCount < 1) iPartyMemberCount = 1; @@ -30,12 +32,12 @@ object GetRandomPartyMember (object oPC) int iPartyMemberCount = GetPartyMemberCount (oPC, 0); int iRandNum = (Random (iPartyMemberCount)+1); if (iRandNum == 1) return oPC; -object oPartyMember = GetFirstFactionMember (oPC); +object oPartyMember = GetFirstFactionMember(oPC); int iCounter; for (iCounter = 1; iCounter < iRandNum; iCounter ++) { if (!GetIsPC(oPartyMember)) iCounter --; - oPartyMember = GetNextFactionMember (oPC); + oPartyMember = GetNextFactionMember(oPC); } return oPartyMember; } @@ -50,7 +52,7 @@ int GetIsOverMaxAllowedLevel (object oPC , object oCaller) if (iPartyMemberLevel > iHighestPartyMemberLevel) iHighestPartyMemberLevel = iPartyMemberLevel; oPartyMember = GetNextFactionMember(oPC); } - int iMaxAllowedLevel = GetMaxAllowedLevel (oCaller); + int iMaxAllowedLevel = GetMaxAllowedLevel(oCaller); if (iHighestPartyMemberLevel > iMaxAllowedLevel) return TRUE; return FALSE; } @@ -78,3 +80,5 @@ void GenerateUniqueTreasure (object oCaller,object oPC) if (LOOT_INC_MAIN_DEBUGGING == TRUE) WriteTimestampedLogEntry (GetTag (oCaller) + " generated " + sItemTemplate); } } + +//:: void main() {} \ No newline at end of file diff --git a/src/module/nss/mm_prc_spells.nss b/src/module/nss/mm_prc_spells.nss new file mode 100644 index 0000000..4aeb8e0 --- /dev/null +++ b/src/module/nss/mm_prc_spells.nss @@ -0,0 +1,161 @@ +#include "0i_menus" +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +json ai_CheckToReplaceSpell(json jSpellList, int nClass, int nLevel, int nSlot) +{ + //if(d100() > 49) return jSpellList; + string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass); + int nRoll = d10() + 1 + nLevel * 10; + int nSpell = StringToInt(Get2DAString("prc_add_spells", sSpellTableColumn, nRoll)); + if(nSpell > 0) + { + //WriteTimestampedLogEntry("mm_prc_spells, 13 nSpell: " + IntToString(nSpell) + + // " nLevel: " + IntToString(nLevel) + " nSlot: " + IntToString(nSlot)); + json jSpellArray = JsonArrayGet(jSpellList, nSlot); + json jSpell = JsonObjectGet(jSpellArray, "Spell"); + jSpell = JsonObjectSet(jSpell, "value", JsonInt(nSpell)); + jSpellArray = JsonObjectSet(jSpellArray, "Spell", jSpell); + return JsonArraySet(jSpellList, nSlot, jSpellArray); + } + return jSpellList; +} +void main() +{ + object oPC = OBJECT_SELF; + if(StartingUp(oPC)) return; + int bChanged, bCreatureChanged, nPosition, nClass, nLevel, nSlot, nMaxSlots; + json jClass, jMemorizedList, jKnownList; + object oModule = GetModule(); + json jCreature = GetLocalJson(oModule, AI_MONSTER_JSON); + object oCreature = GetLocalObject(oModule, AI_MONSTER_OBJECT); + json jClassList = GffGetList(jCreature, "ClassList"); + while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER) + { + nClass = GetClassByPosition(nPosition, oCreature); + if(Get2DAString("classes", "SpellCaster", nClass) == "1") + { + //WriteTimestampedLogEntry("mm_prc_spells, 39 " + GetName(oCreature) + JsonDump(jClassList, 4)); + jClass = JsonArrayGet(jClassList, nPosition - 1); + if(Get2DAString("classes", "MemorizesSpells", nClass) == "1") + { + nLevel = 1; + while(nLevel < 9) + { + jMemorizedList = GffGetList(jClass, "MemorizedList" + IntToString(nLevel)); + if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL) + { + nSlot = 0; + nMaxSlots = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel); + while(nSlot < nMaxSlots) + { + jMemorizedList = ai_CheckToReplaceSpell(jMemorizedList, nClass, nLevel, nSlot); + nSlot++; + } + //WriteTimestampedLogEntry("nClass: " + IntToString(nClass) + " nLevel: " + IntToString(nLevel) + + // " nSlot: " + IntToString(nSlot) + " jMemorizedList " + JsonDump(jMemorizedList, 4)); + jClass = GffReplaceList(jClass, "MemorizedList" + IntToString(nLevel), jMemorizedList); + bChanged = TRUE; + } + nLevel++; + } + } + else + { + nLevel = 1; + while(nLevel < 9) + { + jKnownList = GffGetList(jClass, "KnownList" + IntToString(nLevel)); + if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL) + { + nSlot = 0; + nMaxSlots = GetKnownSpellCount(oCreature, nClass, nLevel); + while(nSlot < nMaxSlots) + { + jKnownList = ai_CheckToReplaceSpell(jKnownList, nClass, nLevel, nSlot); + nSlot++; + } + jClass = GffReplaceList(jClass, "KnownList" + IntToString(nLevel), jKnownList); + bChanged = TRUE; + } + nLevel++; + } + } + if(bChanged) + { + //WriteTimestampedLogEntry("0i_module, 87 " + GetName(oCreature) + " jClass: " + JsonDump(jClass, 4)); + jClassList = JsonArraySet(jClassList, nPosition - 1, jClass); + //if(AI_DEBUG) ai_Debug("0i_module, 89 " + GetName(oCreature) + " jClassList: " + JsonDump(jClassList, 4)); + jCreature = GffReplaceList(jCreature, "ClassList", jClassList); + bCreatureChanged = TRUE; + bChanged = FALSE; + } + } + nPosition++; + } + if(bCreatureChanged) + { + //WriteTimestampedLogEntry("mm_prc_spells, 99 " + GetName(oCreature) + " jClassList: " + JsonDump(jClassList, 4)); + SetLocalJson(oModule, AI_MONSTER_JSON, jCreature); + SetLocalInt(oModule, AI_MONSTER_CHANGED, TRUE); + } +} +int PRCSpellsSetup(object oPC) +{ + // Check to make sure prc_add_spells.2da is loaded. + if(ResManGetAliasFor("prc_add_spells", RESTYPE_2DA) == "") + { + SendMessageToPC(oPC, "prc_add_spells.2da is not loaded! Make sure it is in the override or development folder."); + return FALSE; + } + // Check to make sure PRC is loaded. + if(!GetLocalInt(GetModule(), AI_USING_PRC)) + { + SendMessageToPC(oPC, "PRC is not being used. PRC must be active for this mod to work."); + return FALSE; + } + return TRUE; +} +void SetMonsterModJson(object oPC) +{ + object oModule = GetModule(); + json jMonsterMods = GetLocalJson(oModule, AI_MONSTER_MOD_JSON); + if(JsonGetType(jMonsterMods) == JSON_TYPE_NULL) jMonsterMods = JsonArray(); + int nIndex; + string sMonsterMod = JsonGetString(JsonArrayGet(jMonsterMods, nIndex)); + while(sMonsterMod != "") + { + if(sMonsterMod == "mm_prc_spells") return; + sMonsterMod = JsonGetString(JsonArrayGet(jMonsterMods, ++nIndex)); + } + jMonsterMods = JsonArrayInsert(jMonsterMods, JsonString("mm_prc_spells")); + SetLocalJson(oModule, AI_MONSTER_MOD_JSON, jMonsterMods); + ai_SendMessages("mm_prc_spells loaded! Monsters will be using PRC spells.", AI_COLOR_YELLOW, oPC); +} +int StartingUp(object oPC) +{ + if(!PRCSpellsSetup(oPC)) + { + SendMessageToPC(oPC, "mm_prc_spells monster mod has failed to load due to an error."); + // Return -1 in AI_PLUGIN_SET to tell PEPS that we failed to load. + SetLocalInt(oPC, AI_PLUGIN_SET, -1); + return TRUE; + } + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("mm_prc_spells")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(3)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Monsters will use PRC spells!")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + SetMonsterModJson(oPC); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + SetMonsterModJson(oPC); + return TRUE; +} + diff --git a/src/module/nss/nw_c2_default1.nss b/src/module/nss/nw_c2_default1.nss index 2de3cce..ee29489 100644 --- a/src/module/nss/nw_c2_default1.nss +++ b/src/module/nss/nw_c2_default1.nss @@ -1,106 +1,91 @@ -//::////////////////////////////////////////////////// -//:: NW_C2_DEFAULT1 -/* - Default OnHeartbeat script for NPCs. - - This script causes NPCs to perform default animations - while not otherwise engaged. - - This script duplicates the behavior of the default - script and just cleans up the code and removes - redundant conditional checks. - - */ -//::////////////////////////////////////////////////// -//:: Copyright (c) 2002 Floodgate Entertainment -//:: Created By: Naomi Novik -//:: Created On: 12/22/2002 -//::////////////////////////////////////////////////// - -#include "nw_i0_generic" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default1 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnHeartbeat script; + This will usually fire every 6 seconds (1 game round). +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_module" void main() { - // * if not runnning normal or better Ai then exit for performance reasons - if (GetAILevel() == AI_LEVEL_VERY_LOW) return; - - // Buff ourselves up right away if we should - if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY)) - { - // This will return TRUE if an enemy was within 40.0 m - // and we buffed ourselves up instantly to respond -- - // simulates a spellcaster with protections enabled - // already. - if(TalentAdvancedBuff(40.0)) - { - // This is a one-shot deal - SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE); - - // This return means we skip sending the user-defined - // heartbeat signal in this one case. - return; - } - } - - - if(GetHasEffect(EFFECT_TYPE_SLEEP)) + // If not runnning normal or better AI then exit for performance reasons + if (GetAILevel(OBJECT_SELF) == AI_LEVEL_VERY_LOW) return; + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("nw_c2_default1", "16", GetName(oCreature) + " Heartbeat." + + " OnSpawn: " + IntToString(GetLocalInt(oCreature, AI_ONSPAWN_EVENT))); + // We run our OnSpawn in the heartbeat so the creator can use the original + // OnSpawn for their own use. If we have to recreate the creature then we + // skip the rest of the heartbeat since this version is being destroyed! + if(ai_OnMonsterSpawn(oCreature)) return; + if(AI_DEBUG) ai_Debug("nw_c2_default1", "16", GetName(oCreature) + " Heartbeat." + + " Searching: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING))); + if(ai_GetHasEffectType(oCreature, EFFECT_TYPE_SLEEP)) { // If we're asleep and this is the result of sleeping // at night, apply the floating 'z's visual effect // every so often - if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT)) { effect eVis = EffectVisualEffect(VFX_IMP_SLEEP); if(d10() > 6) { - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCreature); } } } - - // If we have the 'constant' waypoints flag set, walk to the next - // waypoint. - else if ( GetWalkCondition(NW_WALK_FLAG_CONSTANT) ) - { - WalkWayPoints(); - } - - // Check to see if we should be playing default animations - // - make sure we don't have any current targets - else if ( !GetIsObjectValid(GetAttemptedAttackTarget()) - && !GetIsObjectValid(GetAttemptedSpellTarget()) - // && !GetIsPostOrWalking()) - && !GetIsObjectValid(GetNearestSeenEnemy())) - { - if (GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) || GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE) || - GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE)) - { - // This handles special attacking/fleeing behavior - // for omnivores & herbivores. - DetermineSpecialBehavior(); - } - else if (!IsInConversation(OBJECT_SELF)) - { - if (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) - || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN) - || GetIsEncounterCreature()) - { - PlayMobileAmbientAnimations(); - } - else if (GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)) - { - PlayImmobileAmbientAnimations(); - } - } - } - - // Send the user-defined event signal if specified + // Send the user-defined event signal if specified here so it doesn't get skipped. if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)) { - SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_HEARTBEAT)); + SignalEvent(oCreature, EventUserDefined(EVENT_HEARTBEAT)); } - - ExecuteScript("prc_npc_hb", OBJECT_SELF); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature) || + GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return; + if(ai_GetIsInCombat(oCreature)) + { + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE)) + { + object oTarget = ai_GetNearestEnemy(oCreature, 1, 7, 7, -1, -1, TRUE); + if(GetDistanceBetween(oCreature, oTarget) <= 6.0) + { + if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0) + { + SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_coward"); + ActionMoveAwayFromObject(oTarget, TRUE, AI_RANGE_LONG); + return; + } + } + } + ai_DoMonsterCombatRound(oCreature); + return; + } + if(ai_CheckForCombat(oCreature, TRUE)) return; + // If we have not set up our talents then we need to check to see if we should. + if(!GetLocalInt(oCreature, AI_TALENTS_SET)) + { + // We setup our talents when a PC gets withing Battlefield range 40.0 meters. + object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, oCreature, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + if(oPC != OBJECT_INVALID && GetDistanceBetween(oCreature, oPC) <= AI_RANGE_BATTLEFIELD) + { + if(AI_DEBUG) ai_Debug("nw_c2_default1", "72", GetName(oCreature) + " is " + + FloatToString(GetDistanceBetween(oCreature, oPC), 0, 2) + " from " + GetName(oPC)); + if(AI_DEBUG) ai_Debug("nw_c2_default1", "74", GetName(oCreature) + " is Setting Creature Talents and buffing!"); + ai_SetupMonsterBuffTargets(oCreature); + // To save steps and time we set the talents while we buff! + ai_SetCreatureTalents(oCreature, TRUE); + ai_ClearBuffTargets(oCreature, "AI_ALLY_TARGET_"); + } + } + if(!IsInConversation (oCreature)) + { + if(GetWalkCondition(NW_WALK_FLAG_CONSTANT)) WalkWayPoints(); + if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)) PlayMobileAmbientAnimations_NonAvian(); + else if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)) PlayMobileAmbientAnimations_Avian(); + else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)) PlayImmobileAmbientAnimations(); + else if(GetLocalInt(GetModule(), AI_RULE_WANDER) && GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, oCreature) > 89) + { + ai_AmbientAnimations(); + } + } + if(ai_TryHealing(oCreature, oCreature)) return; } diff --git a/src/module/nss/nw_c2_default2.nss b/src/module/nss/nw_c2_default2.nss index 1653553..cdf2362 100644 --- a/src/module/nss/nw_c2_default2.nss +++ b/src/module/nss/nw_c2_default2.nss @@ -1,166 +1,137 @@ -//::////////////////////////////////////////////////// -//:: NW_C2_DEFAULT2 -/* - Default OnPerception event handler for NPCs. - - Handles behavior when perceiving a creature for the - first time. - */ -//::////////////////////////////////////////////////// - -#include "nw_i0_generic" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default2 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnPerception script when not in combat; + There are 4 types of perception - Heard, Inaudible, Seen, Vanished. + Only one type will ever be true in an event trigger. + The order of trigger is Heard/Seen and Inaudible/Vanished. + There are two states of percepion Heard and Seen. + These states can be set at the same time thus a heard event can see the creature. + Fires when ever one of these states changes from TRUE to FALSE or FALSE to TRUE. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" void main() { -// * if not runnning normal or better Ai then exit for performance reasons - // * if not runnning normal or better Ai then exit for performance reasons - if (GetAILevel() == AI_LEVEL_VERY_LOW) return; - - object oPercep = GetLastPerceived(); + // * if not runnning normal or better AI then exit for performance reasons + //if (GetAILevel() == AI_LEVEL_VERY_LOW) return; + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("nw_c2_default2", "19", "AI_ONSPAWN_EVENT: " + IntToString(GetLocalInt(oCreature, AI_ONSPAWN_EVENT))); + if(!GetLocalInt(oCreature, AI_ONSPAWN_EVENT)) return; + if(GetLastPerceptionSeen()) + { + if(AI_DEBUG) ai_Debug("nw_c2_default2", "22", GetName(oCreature) + " sees " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + "."); + } + if(GetLastPerceptionHeard()) + { + if(AI_DEBUG) ai_Debug("nw_c2_default2", "28", GetName(oCreature) + " heard " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + "."); + } + if(GetLastPerceptionVanished ()) + { + if(AI_DEBUG) ai_Debug("nw_c2_default2", "34", GetName(oCreature) + " lost sight of " + + GetName(GetLastPerceived ()) + "."); + } + // We do nothing on Inaudibles so drop out early! + if(GetLastPerceptionInaudible()) + { + if(AI_DEBUG) ai_Debug("nw_c2_default2", "41", GetName(oCreature) + " lost sound of " + + GetName(GetLastPerceived()) + "."); + return; + } + object oLastPerceived = GetLastPerceived(); + if(AI_DEBUG) ai_Debug("nw_c2_default2", "45", "Dead? " + IntToString(GetIsDead(oLastPerceived)) + + " Enemy? " + IntToString(GetIsEnemy(oLastPerceived, oCreature))); + if(ai_Disabled(oCreature)) return; + if(GetIsDead(oLastPerceived)) return; int bSeen = GetLastPerceptionSeen(); - int bHeard = GetLastPerceptionHeard(); - if (bHeard == FALSE) + // This will cause all NPC's to speak their one-liner conversation + // on perception even if they are already in combat. + if(GetIsPC(oLastPerceived) && bSeen) { - // Has someone vanished in front of me? - bHeard = GetLastPerceptionVanished(); - } - - // This will cause the NPC to speak their one-liner - // conversation on perception even if they are already - // in combat. - if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION) - && GetIsPC(oPercep) - && bSeen) - { - SpeakOneLinerConversation(); - } - - // March 5 2003 Brent - // Had to add this section back in, since modifications were not taking this specific - // example into account -- it made invisibility basically useless. - //If the last perception event was hearing based or if someone vanished then go to search mode - if ((GetLastPerceptionVanished()) && GetIsEnemy(GetLastPerceived())) - { - object oGone = GetLastPerceived(); - if((GetAttemptedAttackTarget() == GetLastPerceived() || - GetAttemptedSpellTarget() == GetLastPerceived() || - GetAttackTarget() == GetLastPerceived()) && GetArea(GetLastPerceived()) != GetArea(OBJECT_SELF)) + if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION)) { - ClearAllActions(); - DetermineCombatRound(); + SpeakOneLinerConversation(); } } - - // This section has been heavily revised while keeping the - // pre-existing behavior: - // - If we're in combat, keep fighting. - // - If not and we've perceived an enemy, start to fight. - // Even if the perception event was a 'vanish', that's - // still what we do anyway, since that will keep us - // fighting any visible targets. - // - If we're not in combat and haven't perceived an enemy, - // see if the perception target is a PC and if we should - // speak our attention-getting one-liner. - if (GetIsInCombat(OBJECT_SELF)) + if(GetIsEnemy(oLastPerceived, oCreature)) { - // don't do anything else, we're busy - //MyPrintString("GetIsFighting: TRUE"); - - } - // * BK FEB 2003 Only fight if you can see them. DO NOT RELY ON HEARING FOR ENEMY DETECTION - else if (GetIsEnemy(oPercep) && bSeen) - { // SpawnScriptDebugger(); - //MyPrintString("GetIsEnemy: TRUE"); - // We spotted an enemy and we're not already fighting - if(!GetHasEffect(EFFECT_TYPE_SLEEP)) { - if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) + // ************************** ENEMY SEEN ******************************* + if(bSeen) + { + // If the creature we are perceiving was our invisible creature then + // remove that they are invisible. + if(oLastPerceived == GetLocalObject(oCreature, AI_IS_INVISIBLE)) { - //MyPrintString("DetermineSpecialBehavior"); - DetermineSpecialBehavior(); - } else - { - //MyPrintString("DetermineCombatRound"); - SetFacingPoint(GetPosition(oPercep)); - SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK); - DetermineCombatRound(); + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); } + ai_MonsterEvaluateNewThreat(oCreature, oLastPerceived, AI_I_SEE_AN_ENEMY); } + // ************************** ENEMY HEARD ****************************** + else if(GetLastPerceptionHeard()) + { + ai_MonsterEvaluateNewThreat(oCreature, oLastPerceived, AI_I_HEARD_AN_ENEMY); + } + // ************************** ENEMY VANISHED *************************** + else if(GetLastPerceptionVanished()) + { + // Lets keep a mental note of the invisible creature. + SetLocalObject(oCreature, AI_IS_INVISIBLE, oLastPerceived); + if(AI_DEBUG) ai_Debug("0e_c2_2_percept", "82", " We saw " + GetName(oLastPerceived) + " disappear!"); + if(ai_GetIsBusy(oCreature)) return; + // If in combat check to see if our target disappeared. + // If they have and we are not in melee with them then reevaluate combat + // since we lost our target. + if(ai_GetIsInCombat(oCreature)) + { + if(AI_DEBUG) ai_Debug("nw_c2_default2", "89", "Is this our target? " + + IntToString(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived)); + if(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived) + { + ai_DoMonsterCombatRound(oCreature); + } + } + // We are not in combat so lets move to that location and check it out. + else ActionMoveToLocation(GetLocation(oLastPerceived), TRUE); + // we use to move to the object but thats a bit creepy! + //else ActionMoveToObject(oLastPerceived, TRUE, AI_RANGE_CLOSE); + } + // ************************ ENEMY INAUDIBLE***************************** + // Not used. } else { - if (bSeen) + // ************************ NON_ENEMY SEEN ***************************** + if(bSeen) { - //MyPrintString("GetLastPerceptionSeen: TRUE"); - if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) { - DetermineSpecialBehavior(); - } else if (GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION) - && GetIsPC(oPercep)) + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature); + else if(GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION) && GetIsPC(oLastPerceived)) { - // The NPC will speak their one-liner conversation - // This should probably be: - // SpeakOneLinerConversation(oPercep); - // instead, but leaving it as is for now. - ActionStartConversation(OBJECT_SELF); + ActionStartConversation(oCreature); } } - else - // * July 14 2003: Some minor reactions based on invisible creatures being nearby - if (bHeard && GetIsEnemy(oPercep)) - { - // SpeakString("vanished"); - // * don't want creatures wandering too far after noises - if (GetDistanceToObject(oPercep) <= 7.0) - { -// if (GetHasSpell(SPELL_TRUE_SEEING) == TRUE) - if (GetHasSpell(SPELL_TRUE_SEEING)) - { - ActionCastSpellAtObject(SPELL_TRUE_SEEING, OBJECT_SELF); - } - else -// if (GetHasSpell(SPELL_SEE_INVISIBILITY) == TRUE) - if (GetHasSpell(SPELL_SEE_INVISIBILITY)) - { - ActionCastSpellAtObject(SPELL_SEE_INVISIBILITY, OBJECT_SELF); - } - else -// if (GetHasSpell(SPELL_INVISIBILITY_PURGE) == TRUE) - if (GetHasSpell(SPELL_INVISIBILITY_PURGE)) - { - ActionCastSpellAtObject(SPELL_INVISIBILITY_PURGE, OBJECT_SELF); - } - else - { - ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_LEFT, 0.5); - ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_RIGHT, 0.5); - ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD, 0.5); - } - } - } - - // activate ambient animations or walk waypoints if appropriate - if (!IsInConversation(OBJECT_SELF)) { - if (GetIsPostOrWalking()) { - WalkWayPoints(); - } else if (GetIsPC(oPercep) && - (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) - || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN) - || GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS) - || GetIsEncounterCreature())) - { - SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE); - } - } } - + if(!IsInConversation(oCreature)) + { + if(GetIsPostOrWalking()) + { + WalkWayPoints(); + } + else if(GetIsPC(oLastPerceived) && + (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) || + GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN) || + GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS) || + GetIsEncounterCreature())) + { + SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE); + } + } // Send the user-defined event if appropriate - if(GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) && GetLastPerceptionSeen()) + if(GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) && bSeen) { SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE)); } - - ExecuteScript("prc_npc_percep", OBJECT_SELF); } - - - - diff --git a/src/module/nss/nw_c2_default3.nss b/src/module/nss/nw_c2_default3.nss index 48b6fac..39910ff 100644 --- a/src/module/nss/nw_c2_default3.nss +++ b/src/module/nss/nw_c2_default3.nss @@ -1,57 +1,67 @@ -//:://///////////////////////////////////////////// -//:: Default: End of Combat Round -//:: NW_C2_DEFAULT3 -//:: Copyright (c) 2008 Bioware Corp. -//::////////////////////////////////////////////// -/* - Calls the end of combat script every round -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Oct 16, 2001 -//::////////////////////////////////////////////// -//::////////////////////////////////////////////// -//:: Modified By: Deva Winblood -//:: Modified On: Feb 16th, 2008 -//:: Added Support for Mounted Combat Feat Support -//::////////////////////////////////////////////// - -#include "NW_I0_GENERIC" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default3 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnCombatRoundEnd event script; + Fires at the end of each combat round (6 seconds). + This will fire as long as oCreature is in combat (GetIsInCombat()). + This event starts counting once a combat action is started. + Every time a spell is cast it will queue another end combat round so haste with + two spells cast will fire this twice in one round. + It will also fire at the end of a hostile effect that stops actions i.e Stunned, Knockdown etc. + Action modes are also cleared prior to this event executing! + GetAttemptedAttackTarget() & GetAttemptedSpellTarget() also get cleared prior to this event. + This event can be canceled with ClearAllActions(TRUE) and SurrenderToEnemies. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" void main() { - - if (!GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT")) - { // set variables on target for mounted combat - DeleteLocalInt(OBJECT_SELF,"bX3_LAST_ATTACK_PHYSICAL"); - DeleteLocalInt(OBJECT_SELF,"nX3_HP_BEFORE"); - DeleteLocalInt(OBJECT_SELF,"bX3_ALREADY_MOUNTED_COMBAT"); - if (GetHasFeat(FEAT_MOUNTED_COMBAT,OBJECT_SELF)) - { // check for AC increase - int nRoll=d20()+GetSkillRank(SKILL_RIDE); - nRoll=nRoll-10; - if (nRoll>4) - { // ac increase - nRoll=nRoll/5; - ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectACIncrease(nRoll),OBJECT_SELF,8.5); - } // ac increase - } // check for AC increase - } // set variables on target for mounted combat - - if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) - { - DetermineSpecialBehavior(); - } - else if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS)) - { - DetermineCombatRound(); - } + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("nw_c2_default3", "20", GetName(oCreature) + " ends combat round." + + " Current action: " + IntToString(GetCurrentAction(oCreature))); if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT)) { SignalEvent(OBJECT_SELF, EventUserDefined(1003)); } - - ExecuteScript("prc_npc_combat", OBJECT_SELF); + if(ai_Disabled(oCreature)) return; + // Action modes get cleared prior to each OnCombatRoundEnd! + // We do this to keep the action mode going. + int nActionMode = GetLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + if(nActionMode > 0) + { + SetActionMode(oCreature, nActionMode, TRUE); + // We don't want to use up all of the Dwarven Defenders uses! + if(nActionMode == 12) IncrementRemainingFeatUses(oCreature, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE); + } + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("nw_c2_default3", "37", "nAction: " + IntToString(nAction)); + switch(nAction) + { + // These actions are uninteruptable. + case ACTION_MOVETOPOINT : + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_COUNTERSPELL : return; + // Might be doing a special action that is not a defined action. + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("nw_c2_default3", "49", "nCombatWait: " + IntToString(nCombatWait)); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + } + // We always want to interupt an attack action at the end of a round. + //case ACTION_ATTACKOBJECT : + } + if(ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound (oCreature); + return; + } + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature); } diff --git a/src/module/nss/nw_c2_default4.nss b/src/module/nss/nw_c2_default4.nss index db54b8c..79c34a5 100644 --- a/src/module/nss/nw_c2_default4.nss +++ b/src/module/nss/nw_c2_default4.nss @@ -1,92 +1,69 @@ -//::////////////////////////////////////////////////// -//:: NW_C2_DEFAULT4 -/* - Default OnConversation event handler for NPCs. - - */ -//::////////////////////////////////////////////////// -//:: Copyright (c) 2002 Floodgate Entertainment -//:: Created By: Naomi Novik -//:: Created On: 12/22/2002 -//::////////////////////////////////////////////////// - -#include "nw_i0_generic" - +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_c2_4_convers + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnConversation; + Fires when oCreature has been clicked on for conversation. + Fires when oCreature hears a shout from another creature. + If SetListening is FALSE then oCreature will not "hear" anything. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void ai_MonsterCommands(object oCreature, object oSpeaker, int nMatch); void main() { - // * if petrified, jump out - if (GetHasEffect(EFFECT_TYPE_PETRIFY, OBJECT_SELF) == TRUE) + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("nw_c2_default4", "15", GetName(oCreature) + " listens " + + IntToString(GetListenPatternNumber()) + " to " + GetName(GetLastSpeaker()) + "." + + " AI_AM_I_SEARCHING: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING))); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature) || GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return; + if(ai_GetIsInCombat(oCreature)) { + ai_DoMonsterCombatRound(oCreature); return; } - - // * If dead, exit directly. - if (GetIsDead(OBJECT_SELF) == TRUE) - { - return; - } - - // See if what we just 'heard' matches any of our - // predefined patterns + object oLastSpeaker = GetLastSpeaker(); int nMatch = GetListenPatternNumber(); - object oShouter = GetLastSpeaker(); - - if (nMatch == -1) + if(nMatch != -1) { - // Not a match -- start an ordinary conversation - if (GetCommandable(OBJECT_SELF)) - { - ClearActions(CLEAR_NW_C2_DEFAULT4_29); - BeginConversation(); - } - else - // * July 31 2004 - // * If only charmed then allow conversation - // * so you can have a better chance of convincing - // * people of lowering prices - if (GetHasEffect(EFFECT_TYPE_CHARMED) == TRUE) - { - ClearActions(CLEAR_NW_C2_DEFAULT4_29); - BeginConversation(); - } + if(GetFactionEqual(oLastSpeaker, oCreature)) ai_MonsterCommands(oCreature, oLastSpeaker, nMatch); } - // Respond to shouts from friendly non-PCs only - else if (GetIsObjectValid(oShouter) - && !GetIsPC(oShouter) - && GetIsFriend(oShouter)) + else { - object oIntruder = OBJECT_INVALID; - // Determine the intruder if any - if(nMatch == 4) - { - oIntruder = GetLocalObject(oShouter, "NW_BLOCKER_INTRUDER"); - } - else if (nMatch == 5) - { - oIntruder = GetLastHostileActor(oShouter); - if(!GetIsObjectValid(oIntruder)) - { - oIntruder = GetAttemptedAttackTarget(); - if(!GetIsObjectValid(oIntruder)) - { - oIntruder = GetAttemptedSpellTarget(); - if(!GetIsObjectValid(oIntruder)) - { - oIntruder = OBJECT_INVALID; - } - } - } - } - - // Actually respond to the shout - RespondToShout(oShouter, nMatch, oIntruder); + ai_ClearCreatureActions(); + BeginConversation(); } - // Send the user-defined event if appropriate if(GetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT)) { SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DIALOGUE)); } - - ExecuteScript("prc_npc_conv", OBJECT_SELF); } +void ai_MonsterCommands(object oCreature, object oSpeaker, int nMatch) +{ + object oTarget = GetLocalObject(oSpeaker, AI_MY_TARGET); + if(nMatch == AI_ALLY_SEES_AN_ENEMY || nMatch == AI_ALLY_HEARD_AN_ENEMY) + { + if(AI_DEBUG) ai_Debug("nw_c2_default4", "46", GetName(oCreature) + " heard " + + GetName(oSpeaker) + " has seen an enemy!"); + if(ai_CanIAttack(oCreature)) ai_FindTheEnemy(oCreature, oSpeaker, oTarget, TRUE); + } + else if(nMatch == AI_ALLY_ATKED_BY_WEAPON || + nMatch == AI_ALLY_ATKED_BY_SPELL) + { + if(AI_DEBUG) ai_Debug("nw_c2_default4", "53", GetName(oCreature) + " heard " + + GetName(oSpeaker) + " has been attacked by " + + GetName(GetLocalObject(oSpeaker, AI_MY_TARGET)) + "!"); + if(ai_CanIAttack(oCreature)) ai_FindTheEnemy(oCreature, oSpeaker, oTarget, TRUE); + } + else if(nMatch == AI_ALLY_IS_WOUNDED) + { + if(AI_DEBUG) ai_Debug("nw_c2_default4", "60", GetName(oCreature) + " heard " + + GetName(oSpeaker) + " is wounded!"); + if(ai_GetIsInCombat(oCreature)) ai_TryHealingTalent(oCreature, ai_GetNumOfEnemiesInRange(oCreature), oSpeaker); + else ai_TryHealing(oCreature, oSpeaker); + } + /*else if(nMatch == AI_ALLY_IS_DEAD) + { + } */ +} + diff --git a/src/module/nss/nw_c2_default5.nss b/src/module/nss/nw_c2_default5.nss index 35e79f6..3428057 100644 --- a/src/module/nss/nw_c2_default5.nss +++ b/src/module/nss/nw_c2_default5.nss @@ -1,71 +1,36 @@ -//:://///////////////////////////////////////////// -//:: Default On Attacked -//:: NW_C2_DEFAULT5 -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - If already fighting then ignore, else determine - combat round -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Oct 16, 2001 -//::////////////////////////////////////////////// -//::////////////////////////////////////////////// -//:: Modified By: Deva Winblood -//:: Modified On: Jan 4th, 2008 -//:: Added Support for Mounted Combat Feat Support -//::////////////////////////////////////////////// - -#include "nw_i0_generic" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default5 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnPhysicalAttacked event script; + Fires for all physical attacks, claws, weapons, fists, bow, etc. + Fires for taunt skill, animal empathy skill. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" void main() { - if (!GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT")) - { // set variables on target for mounted combat - SetLocalInt(OBJECT_SELF,"bX3_LAST_ATTACK_PHYSICAL",TRUE); - SetLocalInt(OBJECT_SELF,"nX3_HP_BEFORE",GetCurrentHitPoints(OBJECT_SELF)); - } // set variables on target for mounted combat - - if(GetFleeToExit()) { - // Run away! - ActivateFleeToExit(); - } else if (GetSpawnInCondition(NW_FLAG_SET_WARNINGS)) { - // We give an attacker one warning before we attack - // This is not fully implemented yet - SetSpawnInCondition(NW_FLAG_SET_WARNINGS, FALSE); - - //Put a check in to see if this attacker was the last attacker - //Possibly change the GetNPCWarning function to make the check - } else { - object oAttacker = GetLastAttacker(); - if (!GetIsObjectValid(oAttacker)) { - // Don't do anything, invalid attacker - - } else if (!GetIsFighting(OBJECT_SELF)) { - // We're not fighting anyone else, so - // start fighting the attacker - if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) { - SetSummonHelpIfAttacked(); - DetermineSpecialBehavior(oAttacker); - } else if (GetArea(oAttacker) == GetArea(OBJECT_SELF)) { - SetSummonHelpIfAttacked(); - DetermineCombatRound(oAttacker); - } - - //Shout Attack my target, only works with the On Spawn In setup - SpeakString("NW_ATTACK_MY_TARGET", TALKVOLUME_SILENT_TALK); - - //Shout that I was attacked - SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK); - } + object oCreature = OBJECT_SELF; + object oAttacker = GetLastAttacker(oCreature); + if(AI_DEBUG) ai_Debug("nw_c2_default5", "14", GetName(oCreature) + " was attacked by " + + GetName(oAttacker) + "."); + SetLocalObject(oAttacker, AI_ATTACKED_PHYSICAL, oCreature); + // Run away! + if(ai_GetFleeToExit(oCreature)) + { + ai_ActivateFleeToExit(oCreature); + return; } - - if(GetSpawnInCondition(NW_FLAG_ATTACK_EVENT)) { - SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_ATTACKED)); + SignalEvent(oCreature, EventUserDefined(EVENT_ATTACKED)); } - - ExecuteScript("prc_npc_physatt", OBJECT_SELF); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(ai_GetIsInCombat(oCreature)) return; + // We only inform others if attacked when not busy, not disabled & not in combat. + if(AI_DEBUG) ai_Debug("nw_c2_default5", "30", "Tell my allies I've been attacked!"); + SetLocalObject (oCreature, AI_MY_TARGET, oAttacker); + SpeakString(AI_ATKED_BY_WEAPON, TALKVOLUME_SILENT_TALK); + // Now move towards the attack in the hopes we can see them. + if(GetDistanceBetween(oCreature, oAttacker) < AI_RANGE_CLOSE) ai_DoMonsterCombatRound(oCreature); + else ActionMoveToObject(oAttacker, TRUE, AI_RANGE_CLOSE); } diff --git a/src/module/nss/nw_c2_default6.nss b/src/module/nss/nw_c2_default6.nss index f7f6270..b3532ce 100644 --- a/src/module/nss/nw_c2_default6.nss +++ b/src/module/nss/nw_c2_default6.nss @@ -1,109 +1,33 @@ -//::////////////////////////////////////////////////// -//:: NW_C2_DEFAULT6 -//:: Default OnDamaged handler -/* - If already fighting then ignore, else determine - combat round - */ -//::////////////////////////////////////////////////// -//:: Copyright (c) 2002 Floodgate Entertainment -//:: Created By: Naomi Novik -//:: Created On: 12/22/2002 -//::////////////////////////////////////////////////// -//::////////////////////////////////////////////////// -//:: Modified By: Deva Winblood -//:: Modified On: Jan 17th, 2008 -//:: Added Support for Mounted Combat Feat Support -//::////////////////////////////////////////////////// - -#include "nw_i0_generic" -#include "x3_inc_horse" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default6 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnDamaged event script; + Does not fire if the creature dies from the damage. + Does not fire for plot creatures as they take no damage. + May fire before or after OnPhysicalAttacked event. + Fires when EffectDamage is applied to oCreature even if 0 damage. + Fires when a weapon damages a oCreature, but not if resisted. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" void main() { - object oDamager = GetLastDamager(); - object oMe=OBJECT_SELF; - int nHPBefore; - if (!GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT")) - if (GetHasFeat(FEAT_MOUNTED_COMBAT)&&HorseGetIsMounted(OBJECT_SELF)) - { // see if can negate some damage - if (GetLocalInt(OBJECT_SELF,"bX3_LAST_ATTACK_PHYSICAL")) - { // last attack was physical - nHPBefore=GetLocalInt(OBJECT_SELF,"nX3_HP_BEFORE"); - if (!GetLocalInt(OBJECT_SELF,"bX3_ALREADY_MOUNTED_COMBAT")) - { // haven't already had a chance to use this for the round - SetLocalInt(OBJECT_SELF,"bX3_ALREADY_MOUNTED_COMBAT",TRUE); - int nAttackRoll=GetBaseAttackBonus(oDamager)+d20(); - int nRideCheck=GetSkillRank(SKILL_RIDE,OBJECT_SELF)+d20(); - if (nRideCheck>=nAttackRoll&&!GetIsDead(OBJECT_SELF)) - { // averted attack - if (GetIsPC(oDamager)) SendMessageToPC(oDamager,GetName(OBJECT_SELF)+GetStringByStrRef(111991)); - //if (GetIsPC(OBJECT_SELF)) SendMessageToPCByStrRef(OBJECT_SELF,111992"); - if (GetCurrentHitPoints(OBJECT_SELF) (GetMaxHitPoints(OBJECT_SELF) / 4) - || (GetHitDice(oDamager) - 2) > GetHitDice(oTarget) - ) - ) - ) - { - // Switch targets - DetermineCombatRound(oDamager); - } - } - } - + object oCreature = OBJECT_SELF; // Send the user-defined event signal if(GetSpawnInCondition(NW_FLAG_DAMAGED_EVENT)) { - SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DAMAGED)); + SignalEvent(oCreature, EventUserDefined(EVENT_DAMAGED)); + return; } - - ExecuteScript("prc_npc_damaged", OBJECT_SELF); + if(ai_Disabled(oCreature)) return; + // Make sure to clear wounded shout limit if we take damage. See ai_TryHealing. + DeleteLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT"); + object oDamager = GetLastDamager(oCreature); + if(AI_DEBUG) ai_Debug("nw_c2_default6", "23", GetName(oCreature) + " has been damaged by " + GetName(oDamager)); + if(ai_GetFleeToExit(oCreature)) return; + if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature) || ai_GetIsInCombat(oCreature)) return; + if(GetDistanceBetween(oCreature, oDamager) < AI_RANGE_CLOSE) ai_DoMonsterCombatRound(oCreature); + else ActionMoveToObject(oDamager, TRUE, AI_RANGE_CLOSE - 1.0); } diff --git a/src/module/nss/nw_c2_default8.nss b/src/module/nss/nw_c2_default8.nss index 05529a2..f8225ec 100644 --- a/src/module/nss/nw_c2_default8.nss +++ b/src/module/nss/nw_c2_default8.nss @@ -1,30 +1,24 @@ -//::////////////////////////////////////////////////// -//:: NW_C2_DEFAULT8 -/* - Default OnDisturbed event handler for NPCs. - */ -//::////////////////////////////////////////////////// -//:: Copyright (c) 2002 Floodgate Entertainment -//:: Created By: Naomi Novik -//:: Created On: 12/22/2002 -//::////////////////////////////////////////////////// - -#include "nw_i0_generic" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_default8 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnDisturbed event script; + Fires when the inventory of oCreature is changed i.e. added or removed. + Creatures can't have items added or removed from its inventory (it's not a + container), then the only way this fires for creatures if something is stolen. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" void main() { - object oTarget = GetLastDisturbed(); - - // If we've been disturbed and are not already fighting, - // attack our disturber. - if (GetIsObjectValid(oTarget) && !GetIsFighting(OBJECT_SELF)) { - DetermineCombatRound(oTarget); - } - + if(AI_DEBUG) ai_Debug("nw_c2_default8", "13", GetName(OBJECT_SELF) + " is been disturbed!"); + // We do nothing at the moment... lets not mess up our factions ok? + // This should be defined by the server admins and is commented out. + //if(ai_GetIsBusy(OBJECT_SELF, FALSE) || ai_Disabled()) return; + //object oTarget = GetLastDisturbed(); + //if (oTarget != OBJECT_INVALID) ai_DoMonsterCombatRound (); // Send the disturbed flag if appropriate. - if(GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT)) { + if(GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT)) + { SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DISTURBED)); } - - ExecuteScript("prc_npc_disturb", OBJECT_SELF); } diff --git a/src/module/nss/nw_c2_defaultb.nss b/src/module/nss/nw_c2_defaultb.nss index 6bb7369..570f467 100644 --- a/src/module/nss/nw_c2_defaultb.nss +++ b/src/module/nss/nw_c2_defaultb.nss @@ -1,157 +1,41 @@ -//:://///////////////////////////////////////////// -//:: Default: On Spell Cast At -//:: NW_C2_DEFAULTB -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - This determines if the spell just cast at the - target is harmful or not. - - GZ 2003-Oct-02 : - New AoE Behavior AI. Will use - Dispel Magic against AOES - - Flying Creatures will ignore - Grease - -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Dec 6, 2001 -//:: Last Modified On: 2003-Oct-13 -//::////////////////////////////////////////////// -//::////////////////////////////////////////////// -//:: Modified By: Deva Winblood -//:: Modified On: Jan 4th, 2008 -//:: Added Support for Mounted Combat Feat Support -//::////////////////////////////////////////////// - -#include "nw_i0_generic" -#include "x2_i0_spells" - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_defaultb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monster OnSpellCastAt event script; + Fires when oCreature becomes the target of a spell via SignalEvent. + Fires when a healing kit is used on a creature. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" void main() { + object oCreature = OBJECT_SELF; object oCaster = GetLastSpellCaster(); - - - if(GetLastSpellHarmful()) - { - SetCommandable(TRUE); - - if (!GetLocalInt(GetModule(),"X3_NO_MOUNTED_COMBAT_FEAT")) - { // set variables on target for mounted combat - DeleteLocalInt(OBJECT_SELF,"bX3_LAST_ATTACK_PHYSICAL"); - } // set variables on target for mounted combat - - // ------------------------------------------------------------------ - // If I was hurt by someone in my own faction - // Then clear any hostile feelings I have against them - // After all, we're all just trying to do our job here - // if we singe some eyebrow hair, oh well. - // ------------------------------------------------------------------ - if (GetFactionEqual(oCaster, OBJECT_SELF) == TRUE) - { - ClearPersonalReputation(oCaster, OBJECT_SELF); - ClearAllActions(TRUE); - DelayCommand(1.2, ActionDoCommand(DetermineCombatRound(OBJECT_INVALID))); - // Send the user-defined event as appropriate - if(GetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT)) - { - SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_SPELL_CAST_AT)); - } - return; - } - - int bAttack = TRUE; - // ------------------------------------------------------------------ - // GZ, 2003-Oct-02 - // Try to do something smart if we are subject to an AoE Spell. - // ------------------------------------------------------------------ - if (MatchAreaOfEffectSpell(GetLastSpell()) == TRUE) - { - int nAI = (GetBestAOEBehavior(GetLastSpell())); // from x2_i0_spells - switch (nAI) - { - case X2_SPELL_AOEBEHAVIOR_DISPEL_L: - case X2_SPELL_AOEBEHAVIOR_DISPEL_N: - case X2_SPELL_AOEBEHAVIOR_DISPEL_M: - case X2_SPELL_AOEBEHAVIOR_DISPEL_G: - case X2_SPELL_AOEBEHAVIOR_DISPEL_C: - bAttack = FALSE; - ActionCastSpellAtLocation(nAI, GetLocation(OBJECT_SELF)); - ActionDoCommand(SetCommandable(TRUE)); - SetCommandable(FALSE); - break; - - case X2_SPELL_AOEBEHAVIOR_FLEE: - ClearActions(CLEAR_NW_C2_DEFAULTB_GUSTWIND); - oCaster = GetLastSpellCaster(); - ActionForceMoveToObject(oCaster, TRUE, 2.0); - DelayCommand(1.2, ActionDoCommand(DetermineCombatRound(oCaster))); - bAttack = FALSE; - break; - - case X2_SPELL_AOEBEHAVIOR_IGNORE: - // well ... nothing - break; - - case X2_SPELL_AOEBEHAVIOR_GUST: - ActionCastSpellAtLocation(SPELL_GUST_OF_WIND, GetLocation(OBJECT_SELF)); - ActionDoCommand(SetCommandable(TRUE)); - SetCommandable(FALSE); - bAttack = FALSE; - break; - } - - } - // --------------------------------------------------------------------- - // Not an area of effect spell, but another hostile spell. - // If we're not already fighting someone else, - // attack the caster. - // --------------------------------------------------------------------- - if( !GetIsFighting(OBJECT_SELF) && bAttack) - { - if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) - { - DetermineSpecialBehavior(oCaster); - } - else - { - DetermineCombatRound(oCaster); - } - } - - // We were attacked, so yell for help - SetCommandable(TRUE); - //Shout Attack my target, only works with the On Spawn In setup - SpeakString("NW_ATTACK_MY_TARGET", TALKVOLUME_SILENT_TALK); - - //Shout that I was attacked - SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK); - } - else - { - // --------------------------------------------------------------------- - // July 14, 2003 BK - // If there is a valid enemy nearby and a NON HARMFUL spell has been - // cast on me I should call DetermineCombatRound - // I may be invisible and casting spells on myself to buff myself up - // --------------------------------------------------------------------- - // Fix: JE - let's only do this if I'm currently in combat. If I'm not - // in combat, and something casts a spell on me, it'll make me search - // out the nearest enemy, no matter where they are on the level, which - // is kinda dumb. - object oEnemy =GetNearestEnemy(); - if ((GetIsObjectValid(oEnemy) == TRUE) && (GetIsInCombat() == TRUE)) - { - // SpeakString("keep me in combat"); - DetermineCombatRound(oEnemy); - } - } - + SetLocalObject(oCaster, AI_ATTACKED_SPELL, oCreature); + if(ai_Disabled(oCreature)) return; + if(!GetLastSpellHarmful()) return; // Send the user-defined event as appropriate if(GetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT)) { SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_SPELL_CAST_AT)); } - - ExecuteScript("prc_npc_spellat", OBJECT_SELF); + // If the spell came from an ally, we don't want to hold it against them. + if(GetFactionEqual(oCaster, oCreature)) ClearPersonalReputation(oCaster, oCreature); + // Lets see what kind of area of effect this is and select an appropriate action. + int nSpell = GetLastSpell(); + if(AI_DEBUG) ai_Debug("nw_c2_defaultb", "26", GetName(oCreature) + " has been hit by a harmful spell(" + + Get2DAString("spells", "Label", nSpell) + ")!"); + if(ai_GetInAOEReaction(oCreature, oCaster, nSpell) && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature)) return; + if(ai_CheckForCombat(oCreature, TRUE)) return; + // We have been attacked out of combat, so let our allies know. + SetLocalObject(oCreature, AI_MY_TARGET, oCaster); + SpeakString(AI_ATKED_BY_SPELL, TALKVOLUME_SILENT_TALK); + if(GetDistanceBetween(oCreature, oCaster) < AI_RANGE_CLOSE) + { + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature); + else ai_DoMonsterCombatRound(oCreature); + } + else ActionMoveToObject(oCaster, TRUE, AI_RANGE_CLOSE); } diff --git a/src/module/nss/nw_c2_defaulte.nss b/src/module/nss/nw_c2_defaulte.nss index d5a32e5..76f62db 100644 --- a/src/module/nss/nw_c2_defaulte.nss +++ b/src/module/nss/nw_c2_defaulte.nss @@ -1,51 +1,53 @@ -//:://///////////////////////////////////////////// -//:: Default On Blocked -//:: NW_C2_DEFAULTE -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - This will cause blocked creatures to open - or smash down doors depending on int and - str. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Nov 23, 2001 -//::////////////////////////////////////////////// - +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_defaulte + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monsters OnBlocked event script; + Can be blocked by a creature or door. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" void main() { - object oDoor = GetBlockingDoor(); - if (GetObjectType(oDoor) == OBJECT_TYPE_CREATURE) + object oCreature = OBJECT_SELF; + // This actually gets either a Creature or Door that is blocking OBJECT_SELF. + object oObject = GetBlockingDoor(); + if(AI_DEBUG) ai_Debug("nw_c2_defaulte", "14", GetName(oCreature) + " is being blocked by " + GetName(oObject)); + int nObjectType = GetObjectType(oObject); + if(nObjectType == OBJECT_TYPE_CREATURE) { - // * Increment number of times blocked - /*SetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED", GetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED") + 1); - if (GetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED") > 3) + if(GetIsEnemy(oObject, oCreature)) { - SpeakString("Blocked by creature"); - SetLocalInt(OBJECT_SELF, "X2_NUMTIMES_BLOCKED",0); - ClearAllActions(); - object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); - if (GetIsObjectValid(oEnemy) == TRUE) + if(ai_CanIAttack(oCreature) && ai_GetIsInCombat(oCreature)) { - ActionEquipMostDamagingRanged(oEnemy); - ActionAttack(oEnemy); + ai_DoMonsterCombatRound(oCreature); + return; } - return; - } */ + if(ai_CheckForCombat(oCreature, TRUE)) return; + } + } + // Anything below blocking us is a door. + if(nObjectType != OBJECT_TYPE_DOOR) return; + // Only open the door if the player has turned door opening on. + if(!GetLocalInt(GetModule(), AI_RULE_OPEN_DOORS)) return; + //if(GetLockKeyTag(oObject) != "") return; + else if(GetIsDoorActionPossible(oObject, DOOR_ACTION_OPEN) && + GetAbilityScore(oCreature, ABILITY_INTELLIGENCE) >= 5) + { + if(AI_DEBUG) ai_Debug("nw_c2_defaulte", "33", GetName(oCreature) + " is opening " + GetName(oObject)); + DoDoorAction(oObject, DOOR_ACTION_OPEN); return; } - if(GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) >= 5) + // If we are in combat we should ignore doors that do not easily open. + if(GetIsDoorActionPossible(oObject, DOOR_ACTION_BASH) && + ai_GetWeaponDamage(oCreature, 3, TRUE) > GetHardness(oObject) && + GetLockKeyTag(oObject) == "") { - if(GetIsDoorActionPossible(oDoor, DOOR_ACTION_OPEN) && GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) >= 7 ) - { - DoDoorAction(oDoor, DOOR_ACTION_OPEN); - } - else if(GetIsDoorActionPossible(oDoor, DOOR_ACTION_BASH)) - { - DoDoorAction(oDoor, DOOR_ACTION_BASH); - } + ActionWait(1.0); + ActionAttack(oObject); + // Give them 3 rounds to break through a door. + DelayCommand(18.0, ai_ClearCreatureActions(TRUE)); + return; } - - ExecuteScript("prc_npc_blocked", OBJECT_SELF); } + + diff --git a/src/module/nss/nw_ch_ac1.nss b/src/module/nss/nw_ch_ac1.nss new file mode 100644 index 0000000..6ed2fea --- /dev/null +++ b/src/module/nss/nw_ch_ac1.nss @@ -0,0 +1,158 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac1 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate(Summons, Familiar, Companion) OnHeart beat script when out of combat; + This will usually fire every 6 seconds (1 game round). +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_module" +#include "0i_menus" +void ai_ActionFollow(object oCreature, object oTarget) +{ + if(GetLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE) == AI_LAST_ACTION_MOVE) + { + float fDistance = GetDistanceBetween(oCreature, oTarget); + float fFollowDistance = ai_GetFollowDistance(oCreature); + if(fDistance > fFollowDistance) + { + if(fDistance > fFollowDistance * 5.0 && + ai_GetIsInCombat(oCreature)) AssignCommand(oCreature, JumpToObject(oTarget)); + else + { + ClearAllActions(); + ActionMoveToObject(oTarget, TRUE, fFollowDistance); + } + } + DelayCommand(1.0, ai_ActionFollow(oCreature, oTarget)); + } +} +void main() +{ + if (GetAILevel(OBJECT_SELF) == AI_LEVEL_VERY_LOW) return; + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Counter_Start(); + // We run our OnSpawn in the heartbeat so the creator can use the original + // OnSpawn for their own use. + ai_OnAssociateSpawn(oCreature); + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_OnAssociateSpawn"); + if(AI_DEBUG) ai_Debug("nw_ch_ac1", "37", GetName(oCreature) + " Heartbeat." + + " MODE_FOLLOW: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) + + " Action: " + IntToString(GetCurrentAction(oCreature))); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_GetIsBusy/ai_Disabled"); + // If we are an associate and don't have a master then exit. + object oMaster = GetMaster(oCreature); + if(AI_DEBUG) ai_Debug("nw_ch_ac1", "43", "oMaster: " + GetName(oMaster)); + if(oMaster == OBJECT_INVALID) + { + if(ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound(oCreature); + return; + } + ai_CheckForCombat(oCreature, FALSE); + return; + } + // ***** Code for Henchman data and menus ***** + if(ai_GetIsCharacter(oMaster)) + { + string sAssociateType = ai_GetAssociateType(oMaster, oCreature); + ai_CheckAssociateData(oMaster, oCreature, sAssociateType); + ai_CheckPCStart(oMaster); + if(AI_HENCHMAN_WIDGET) + { + // This keeps widgets from disappearing and reappearing. + int nUiToken = NuiFindWindow(oMaster, sAssociateType + AI_WIDGET_NUI); + if(nUiToken) + { + json jData = NuiGetUserData(oMaster, nUiToken); + object oAssociate = StringToObject(JsonGetString(JsonArrayGet(jData, 0))); + if(oAssociate != oCreature) NuiDestroy(oMaster, nUiToken); + } + else + { + if(!ai_GetWidgetButton(oMaster, BTN_WIDGET_OFF, oCreature, sAssociateType)) + { + ai_CreateWidgetNUI(oMaster, oCreature); + } + } + } + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, Get Associate data/Build widget"); + } + // If follow mode we do not want the NPC doing anything but follow. + if(!ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) + { + if(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) + { + ai_TryHealing(oCreature, oCreature); + return; + } + if(ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound(oCreature); + return; + } + if(ai_CheckForCombat(oCreature, FALSE)) return; + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_CheckForCombat"); + if(IsInConversation(oCreature)) return; + // In command mode we let the player tell us what to do. + if(!ai_GetAIMode(oCreature, AI_MODE_COMMANDED)) + { + if(ai_TryHealing(oCreature, oCreature)) return; + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat: TryHealing"); + if(ai_CheckNearbyObjects(oCreature)) return; + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat: CheckNearbyObjects"); + if(ai_GetAIMode(oCreature, AI_MODE_SCOUT_AHEAD)) + { + ai_ScoutAhead(oCreature); + return; + } + } + } + // Finally we check to make sure we are following our master. + if(GetCurrentAction(oCreature) != ACTION_FOLLOW) + { + //ai_Debug("nw_ch_ac1", "66", "Follow master: " + + // " Stealth: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) + + // " Search: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH))); + if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) + { + if(AI_DEBUG) ai_Debug("nw_ch_ac1", "120", "Going into stealth mode!"); + int nStealth = GetSkillRank(SKILL_HIDE, oCreature); + nStealth += GetSkillRank(SKILL_MOVE_SILENTLY, oCreature); + if(nStealth / 2 >= ai_GetCharacterLevels(oCreature)) + { + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + } + } + else + { + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH)) + { + if(AI_DEBUG) ai_Debug("nw_ch_ac1", "134", "Going into search mode!"); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + } + else SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + } + // Follow master. + if(GetDistanceBetween(oCreature, oMaster) > ai_GetFollowDistance(oCreature)) + { + if(!ai_GetAIMode(oCreature, AI_MODE_COMMANDED)) + { + object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oMaster; + //ActionForceFollowObject(oTarget, ai_GetFollowDistance(oCreature)); + //ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oCreature)); + SetLocalInt(oCreature, AI_CURRENT_ACTION_MODE, AI_LAST_ACTION_MOVE); + ai_ActionFollow(oCreature, oTarget); + } + } + } + if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, end"); + if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1001)); + } +} diff --git a/src/module/nss/nw_ch_ac2.nss b/src/module/nss/nw_ch_ac2.nss new file mode 100644 index 0000000..04a56f9 --- /dev/null +++ b/src/module/nss/nw_ch_ac2.nss @@ -0,0 +1,107 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac2 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate(Summons, Familiars, Companions) OnPerception script when not in combat; + There are 4 types of perception - Heard, Inaudible, Seen, Vanished. + Only one type will ever be true in an event trigger. + The order of trigger is Heard/Seen and Inaudible/Vanished. + There are two states of percepion Heard and Seen. + These states can be set at the same time thus a heard event can see the creature. + Fires when ever one of these states changes from TRUE to FALSE or FALSE to TRUE. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oLastPerceived = GetLastPerceived(); + if(AI_DEBUG) + { + if(GetLastPerceptionHeard ()) + { + ai_Debug("nw_ch_ac2", "21", GetName(oCreature) + " heard " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + + " Seen: " + IntToString(GetObjectSeen(oLastPerceived, oCreature)) + "."); + } + if(GetLastPerceptionSeen ()) + { + ai_Debug("nw_ch_ac2", "29", GetName(oCreature) + " sees " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + "."); + } + if(GetLastPerceptionVanished ()) + { + ai_Debug("nw_ch_ac2", "35", GetName(oCreature) + " lost sight of " + + GetName(GetLastPerceived()) + "."); + } + } + // We do nothing on Inaudibles so drop out early! + if(GetLastPerceptionInaudible()) + { + ai_Debug("nw_ch_ac2", "42", GetName(oCreature) + " lost sound of " + + GetName(GetLastPerceived()) + "."); + return; + } + if(AI_DEBUG) ai_Debug("nw_ch_ac2", "46", "Dead? " + IntToString(GetIsDead(oLastPerceived)) + + " Enemy? " + IntToString(GetIsEnemy(oLastPerceived, oCreature))); + if(ai_Disabled(oCreature)) return; + if(GetIsDead(oLastPerceived) || !GetIsEnemy(oLastPerceived, oCreature)) return; + // All code below assumes the perceived creature is an enemy and is alive! + // **************************** ENEMY HEARD ******************************** + if(GetLastPerceptionHeard()) + { + // Since Heard is run before Seen, but the values are set at the same + // time we can skip heard checks on heard & seen creatures! + if(GetObjectSeen(oLastPerceived, oCreature)) + { + // If the creature we are perceiving was our invisible creature then + // remove that they are invisible. + if(oLastPerceived == GetLocalObject(oCreature, AI_IS_INVISIBLE)) + { + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); + } + ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_SEE_AN_ENEMY); + } + else ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_HEARD_AN_ENEMY); + return; + } + // **************************** ENEMY SEEN ********************************* + if(GetLastPerceptionSeen()) + { + // If the creature we are perceiving was our invisible creature then + // remove that they are invisible. + if(oLastPerceived == GetLocalObject(oCreature, AI_IS_INVISIBLE)) + { + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); + } + ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_SEE_AN_ENEMY); + return; + } + // **************************** ENEMY VANISHED ***************************** + if(GetLastPerceptionVanished()) + { + // Lets keep a mental note of the invisible creature. + SetLocalObject(oCreature, AI_IS_INVISIBLE, oLastPerceived); + if(AI_DEBUG) ai_Debug("nw_ch_ac2", "86", " We saw " + GetName(oLastPerceived) + " disappear!"); + if(ai_GetIsBusy(oCreature)) return; + // If in combat check to see if our target disappeared. + // If they have and we are not in melee with them then reevaluate combat + // since we lost our target. + if(ai_GetIsInCombat(oCreature)) + { + if(AI_DEBUG) ai_Debug("nw_ch_ac2", "93", "Is this our target? " + + IntToString(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived)); + if(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived) + { + ai_DoAssociateCombatRound(oCreature); + } + return; + } + // If they are not invisible then that means they left our perception + // range and we need follow them. + if(ai_CanIAttack(oCreature)) ActionMoveToObject(oLastPerceived, TRUE, AI_RANGE_CLOSE); + } + // **************************** ENEMY INAUDIBLE***************************** + // Not used. +} diff --git a/src/module/nss/nw_ch_ac3.nss b/src/module/nss/nw_ch_ac3.nss new file mode 100644 index 0000000..9eb3406 --- /dev/null +++ b/src/module/nss/nw_ch_ac3.nss @@ -0,0 +1,56 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac3 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate (Summons, Familiars, Companions) OnCombatRoundEnd event script; + Fires at the end of each combat round (6 seconds). + This will fire as long as oCreature is in combat (GetIsInCombat()). + This event starts counting once a combat action is started. + Every time a spell is cast it will queue another end combat round so haste with + two spells cast will fire this twice in one round. + It will also fire at the end of a hostile effect that stops actions i.e Stunned, Knockdown etc. + Action modes are also cleared prior to this event executing! + GetAttemptedAttackTarget() & GetAttemptedSpellTarget() also get cleared prior to this event. + This event can be canceled with ClearAllActions(TRUE) and SurrenderToEnemies. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("nw_ch_ac3", "20", GetName(oCreature) + " ends combat round."); + if(ai_Disabled(oCreature)) return; + // Action modes get cleared prior to each OnCombatRoundEnd! + // We do this to keep the action mode going. + int nActionMode = GetLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + if(nActionMode > 0) + { + SetActionMode(oCreature, nActionMode, TRUE); + // We don't want to use up all of the Dwarven Defenders uses! + if(nActionMode == 12) IncrementRemainingFeatUses(oCreature, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE); + } + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("nw_ch_ac3", "32", "nAction: " + IntToString(nAction)); + switch(nAction) + { + // These actions are uninteruptable. + case ACTION_MOVETOPOINT : + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_COUNTERSPELL : return; + // Might be doing a special action that is not a defined action. + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("nw_ch_ac3", "44", "nCombatWait: " + IntToString(nCombatWait)); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + } + // We always want to interupt an attack action at the end of a round. + //case ACTION_ATTACKOBJECT : + } + if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound (oCreature); +} + diff --git a/src/module/nss/nw_ch_ac4.nss b/src/module/nss/nw_ch_ac4.nss new file mode 100644 index 0000000..f6c290d --- /dev/null +++ b/src/module/nss/nw_ch_ac4.nss @@ -0,0 +1,45 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac4 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate(Summons, Familiar, Companion) OnDialoge event script; + Fires when oCreature has been clicked on for conversation. + Fires when oCreature hears a shout from another creature. + If SetListening is FALSE then oCreature will not "hear" anything. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +#include "nw_inc_gff" +void main() +{ + object oCreature = OBJECT_SELF; + int nMatch = GetListenPatternNumber(); + if(AI_DEBUG) ai_Debug("nw_ch_ac4", "16", GetName(oCreature) + " listens " + + IntToString(nMatch) + " to " + GetName(GetLastSpeaker()) + "."); + // Skip ASSOCIATE_COMMAND_MASTERUNDERATTACK(11) since it fires for + // every physical attack made on our master. This fires alot! + if(nMatch == ASSOCIATE_COMMAND_MASTERUNDERATTACK) return; + // If we are disabled then we can't listen or talk, Busy is checked in ai_SelectAssociateCommand(). + if(ai_Disabled(oCreature)) return; + object oLastSpeaker = GetLastSpeaker(); + // Some commands override being busy so we check in ai_SelectAssociateCommand. + if(nMatch != -1) + { + if(GetFactionEqual(oLastSpeaker, oCreature)) ai_SelectAssociateCommand(oCreature, oLastSpeaker, nMatch); + } + else + { + if (!ai_GetIsBusy(oCreature)) + { + ai_ClearCreatureActions(); + if(GetAssociateType(oCreature) == ASSOCIATE_TYPE_HENCHMAN) BeginConversation("oc_ai_henchmen", oLastSpeaker); + else + { + json jHenchman = ObjectToJson(oCreature); + string sConversation = JsonGetString(GffGetResRef(jHenchman, "Conversation")); + if(sConversation == "") BeginConversation("oc_ai_henchmen", oLastSpeaker); + BeginConversation(); + } + } + } +} + diff --git a/src/module/nss/nw_ch_ac5.nss b/src/module/nss/nw_ch_ac5.nss new file mode 100644 index 0000000..78f9321 --- /dev/null +++ b/src/module/nss/nw_ch_ac5.nss @@ -0,0 +1,51 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac5 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associates (Summons, Familiars, Companions) OnPhysicalAttacked event script; + Fires for all physical attacks, claws, weapons, fists, bow, etc. + Fires for taunt skill, animal empathy skill. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oAttacker = GetLastAttacker(); + if(AI_DEBUG) ai_Debug("nw_ch_ac5", "14", GetName(oCreature) + " was attacked by " + + GetName(oAttacker) + "."); + SetLocalObject(oAttacker, AI_ATTACKED_PHYSICAL, oCreature); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(GetSpawnInCondition(NW_FLAG_ATTACK_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1005)); + } + if(ai_GetIsInCombat(oCreature)) return; + // We only inform others if attacked when not busy, not disabled, & not in combat. + SetLocalObject(oCreature, AI_MY_TARGET, oAttacker); + SpeakString(AI_ATKED_BY_WEAPON, TALKVOLUME_SILENT_TALK); + // If they are using a melee weapon then make sure we are using our perception range. + // Don't go running towards them just yet, but if its a ranged weapon then react. + if(ai_GetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oAttacker))) + { + float fDistance = GetDistanceBetween(oCreature, oAttacker); + float fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE); + if(fDistance > fPerceptionDistance) return; + } + int nAction = GetCurrentAction(oCreature); + float fDistance = GetDistanceBetween(oCreature, oAttacker); + if(!ai_CanIAttack(oCreature)) + { + // We should defend ourselves if we are in Hold mode. + if(!ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) return; + // Only defend against melee attacks. + if(fDistance > AI_RANGE_MELEE) return; + } + // The only way to get here is to not be in combat. + if(fDistance < AI_RANGE_CLOSE) + { + ai_StartAssociateCombat(oCreature); + } + else ActionMoveToObject(oAttacker, TRUE, AI_RANGE_CLOSE - 1.0); +} + + diff --git a/src/module/nss/nw_ch_ac6.nss b/src/module/nss/nw_ch_ac6.nss new file mode 100644 index 0000000..f51e937 --- /dev/null +++ b/src/module/nss/nw_ch_ac6.nss @@ -0,0 +1,32 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_ch_6_damaged + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnDamaged script for PC AI; + Does not fire if the creature dies from the damage. + Does not fire for plot creatures as they take no damage. + May fire before or after OnPhysicalAttacked event. + Fires when EffectDamage is applied to oCreature even if 0 damage. + Fires when a weapon damages a oCreature, but not if resisted. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + if(ai_Disabled(oCreature)) return; + // Make sure to clear wounded shout limit if we take damage. See ai_TryHealing. + DeleteLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT"); + object oDamager = GetLastDamager(oCreature); + if(AI_DEBUG) ai_Debug("nw_ch_ac6", "18", GetName(oCreature) + " has been damaged by " + GetName(oDamager)); + if(GetSpawnInCondition(NW_FLAG_DAMAGED_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1006)); + } + if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature) || ai_GetIsInCombat(oCreature)) return; + if(!ai_CanIAttack(oCreature)) return; + if(GetDistanceBetween(oCreature, oDamager) < AI_RANGE_CLOSE) ai_DoAssociateCombatRound(oCreature); + else ActionMoveToObject(oDamager, TRUE, AI_RANGE_CLOSE - 1.0); +} + diff --git a/src/module/nss/nw_ch_ac8.nss b/src/module/nss/nw_ch_ac8.nss new file mode 100644 index 0000000..05b7f85 --- /dev/null +++ b/src/module/nss/nw_ch_ac8.nss @@ -0,0 +1,25 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_ac8 + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associates (Summons, Familiars, Companions) OnDisturbed event script. + Fires when the inventory of oCreature is changed i.e. added or removed. + Creatures can't have items added or removed from its inventory (it's not a + container), then the only way this fires for creatures if something is stolen. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + if(AI_DEBUG) ai_Debug("nw_ch_ac8", "13", GetName(OBJECT_SELF) + " is been disturbed!"); + if(GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1008)); + } + // We do nothing at the moment... lets not mess up our factions ok? + // This should be defined by the server admins and is commented out. + //if(ai_GetIsBusy(OBJECT_SELF, FALSE) || ai_Disabled()) return; + //object oTarget = GetLastDisturbed(); + //if (oTarget != OBJECT_INVALID) ai_DoMonsterCombatRound (); +} + + diff --git a/src/module/nss/nw_ch_aca.nss b/src/module/nss/nw_ch_aca.nss new file mode 100644 index 0000000..99b6d5f --- /dev/null +++ b/src/module/nss/nw_ch_aca.nss @@ -0,0 +1,46 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_aca + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate OnRested event script; + Fires when the creature attempts to rest via ActionRest or a PC rests. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_menus" +void ai_UpdateAssociateWidget(object oMaster, object oAssociate, int nUIToken) +{ + if(nUIToken) NuiDestroy(oMaster, nUIToken); + ai_CreateWidgetNUI(oMaster, oAssociate); + if(oMaster != oAssociate) + { + nUIToken = NuiFindWindow(oMaster, "pc" + AI_WIDGET_NUI); + if(nUIToken) + { + NuiDestroy(oMaster, nUIToken); + ai_CreateWidgetNUI(oMaster, oMaster); + } + } +} +void main() +{ + object oAssociate = OBJECT_SELF; + ai_ClearCreatureActions(); + ai_OnRested(oAssociate); + object oMaster = GetMaster(oAssociate); + if(ai_GetIsCharacter(oMaster) && AI_HENCHMAN_WIDGET) + { + int nLevel = ai_GetCharacterLevels(oAssociate); + float fDelay = StringToFloat(Get2DAString("restduration", "DURATION", nLevel)); + fDelay = (fDelay / 1000.0f) + 6.0f; + // Update widget for spell widget. + string sAssociateType = ai_GetAssociateType(oMaster, oAssociate); + int nUIToken = NuiFindWindow(oMaster, sAssociateType + AI_WIDGET_NUI); + if(nUIToken) DelayCommand(fDelay, ai_UpdateAssociateWidget(oMaster, oAssociate, nUIToken)); + else + { + if(!ai_GetWidgetButton(oMaster, BTN_WIDGET_OFF, oAssociate, sAssociateType)) + { + DelayCommand(fDelay, ai_UpdateAssociateWidget(oMaster, oAssociate, 0)); + } + } + } +} diff --git a/src/module/nss/nw_ch_acb.nss b/src/module/nss/nw_ch_acb.nss new file mode 100644 index 0000000..ec96e77 --- /dev/null +++ b/src/module/nss/nw_ch_acb.nss @@ -0,0 +1,42 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_ch_acb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associates (Summons, Familiars, Companions) OnSpellCastAt event script; + Fires when oCreature becomes the target of a spell via SignalEvent. + Fires when a healing kit is used on a creature. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oCaster = GetLastSpellCaster(); + SetLocalObject(oCaster, AI_ATTACKED_SPELL, oCreature); + if(ai_Disabled(oCreature)) return; + if(!GetLastSpellHarmful()) return; + // If the spell came from an ally, we don't want to hold it against them. + if(GetFactionEqual(oCaster, oCreature)) + { + ClearPersonalReputation(oCaster, oCreature); + if(GetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_SPELL_CAST_AT)); + } + } + // Lets see what kind of area of effect this is and select an appropriate action. + int nSpell = GetLastSpell(); + if(AI_DEBUG) ai_Debug("nw_ch_acb", "21", GetName(OBJECT_SELF) + " has been hit by a harmful spell(" + + Get2DAString("spells", "Label", nSpell) + ")!"); + if(ai_GetInAOEReaction(oCreature, oCaster, nSpell) && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature)) return; + if(ai_CheckForCombat(oCreature, FALSE)) return; + // We were attacked by an enemy out of combat, so let our allies know. + SetLocalObject(oCreature, AI_MY_TARGET, oCaster); + SpeakString(AI_ATKED_BY_SPELL, TALKVOLUME_SILENT_TALK); + if(!ai_CanIAttack(oCreature)) return; + if(GetDistanceBetween(oCreature, oCaster) < AI_RANGE_CLOSE) ai_DoAssociateCombatRound(oCreature); + else ActionMoveToObject(oCaster, TRUE, AI_RANGE_CLOSE - 1.0); +} + + diff --git a/src/module/nss/nw_ch_ace.nss b/src/module/nss/nw_ch_ace.nss new file mode 100644 index 0000000..688ab90 --- /dev/null +++ b/src/module/nss/nw_ch_ace.nss @@ -0,0 +1,60 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: 0e_ch_e_blocked + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associates OnBlocked event script; + Can be blocked by a creature or door. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + // This actually gets either a Creature or Door that is blocking OBJECT_SELF. + object oObject = GetBlockingDoor(); + if(AI_DEBUG) ai_Debug("nw_ch_ace", "14", GetName(oCreature) + " is being blocked by " + GetName(oObject)); + int nObjectType = GetObjectType(oObject); + if(nObjectType == OBJECT_TYPE_CREATURE) + { + if(GetIsEnemy(oObject, oCreature)) + { + if(ai_CanIAttack(oCreature) && ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound(oCreature); + return; + } + if(ai_CheckForCombat(oCreature, FALSE)) return; + } + } + // Anything below blocking us is a door. + if(nObjectType != OBJECT_TYPE_DOOR) return; + if(!ai_GetAIMode(oCreature, AI_MODE_OPEN_DOORS)) return; + //if(GetLockKeyTag(oObject) != "") return; + else if(GetIsDoorActionPossible(oObject, DOOR_ACTION_OPEN) && + GetAbilityScore(oCreature, ABILITY_INTELLIGENCE) >= 5) + { + DoDoorAction(oObject, DOOR_ACTION_OPEN); + return; + } + // Anything below is ignored in combat. + if(ai_GetIsInCombat(oCreature)) return; + if(GetIsDoorActionPossible(oObject, DOOR_ACTION_BASH) && + ai_GetWeaponDamage(oCreature, 3, TRUE) > GetHardness(oObject) && + GetLockKeyTag(oObject) == "") + { + ActionWait(1.0); + ActionAttack(oObject); + // Give them 3 rounds to break through a door. + DelayCommand(18.0, ai_ClearCreatureActions(TRUE)); + return; + } + else if(GetLocked(oObject)) + { + if(AI_DEBUG) ai_Debug("nw_ch_ace", "49", GetName(oObject) + " is locked!"); + ai_AttemptToByPassLock(oCreature, oObject); + } + // Clear our action so we can move on to something else unless the door is open. + else if(!GetIsOpen(oObject)) + { + ai_ClearCreatureActions(); + } +} diff --git a/src/module/nss/nw_ch_summon_9.nss b/src/module/nss/nw_ch_summon_9.nss new file mode 100644 index 0000000..ca5a87c --- /dev/null +++ b/src/module/nss/nw_ch_summon_9.nss @@ -0,0 +1,40 @@ +//:://///////////////////////////////////////////// +//:: Associate: On Spawn In +//:: nw_ch_summon_9 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + +This must support the OC henchmen and all summoned/companion +creatures. + +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Nov 19, 2001 +//::////////////////////////////////////////////// +//:: Updated By: Georg Zoeller, 2003-08-20: Added variable check for spawn in animation +#include "X0_INC_HENAI" +#include "x2_inc_switches" +void main() +{ + //Sets up the special henchmen listening patterns + SetAssociateListenPatterns(); + + // Set additional henchman listening patterns + //bkSetListeningPatterns(); + // * If Incorporeal, apply changes + if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE) + { + effect eConceal = EffectConcealment(50, MISS_CHANCE_TYPE_NORMAL); + eConceal = ExtraordinaryEffect(eConceal); + effect eGhost = EffectCutsceneGhost(); + eGhost = ExtraordinaryEffect(eGhost); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eConceal, OBJECT_SELF); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, OBJECT_SELF); + } + // Set starting location + SetAssociateStartLocation(); +} + + diff --git a/src/module/nss/pc_savebuffs.nss b/src/module/nss/pc_savebuffs.nss new file mode 100644 index 0000000..96b42d0 --- /dev/null +++ b/src/module/nss/pc_savebuffs.nss @@ -0,0 +1,182 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pc_savebuffs +//////////////////////////////////////////////////////////////////////////////// + Used with pi_buffing to run the buffing plugin for + Philos Single Player Enhancements. + +Note: If a spell saves incorrectly check the spell script to see if the correct +spell is being passed through the SignalEvent correctly. +Known error in Shield of Faith spell as the below code in the shield of faith +script sends Camoflage instead! +"SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 421, FALSE));" +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag = ""); +// sDataField should be one of the data fields for that table. +// sData is the string data to be saved. +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag = ""); +// sDataField should be one of the data fields for that table. +// jData is the json data to be saved. +void SetBuffDatabaseJson(object oPlayer, string sDataField, json jData, string sTag = ""); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +json GetBuffDatabaseJson(object oPlayer, string sDataField, string sTag = ""); +// Returns the level if this spell has a domain spell on nLevel, or 0. +int GetHasDomainSpell(object oCaster, int nClass, int nLevel, int nSpell); + +// We do some crazy hack to get all the correct information when casting spells. +// GetLastSpellCastClass() will only give the class if this script is running +// on the actual caster, i.e. our PC. +// GetLastSpellLevel() will only give the level if this script is running on +// the actual caster, i.e. our PC. +// So for this to work we run this scrip in the event OnSpellCastAt of our +// target, then we ExecuteScript this script again with the Caster (oPC) +// as OBJECT_SELF for this script on its second pass. This allows us to get the +// information from the above functions! Neat! +void main() +{ + object oTarget = OBJECT_SELF; + // The first pass we get oCaster via GetLastSpellCaster() fails in ExecuteScript! + // The second pass we get oCaster via the variable "AI_BUFF_CASTER". + object oCaster = GetLocalObject(oTarget, "AI_BUFF_CASTER"); + if(oCaster == OBJECT_INVALID) oCaster = GetLastSpellCaster(); + // We setting up the save spells button we saved the PC to itself. + // Here we get the PC to make sure the caster of this spell is our saving PC. + object oPC = GetLocalObject(oCaster, "AI_BUFF_PC"); + // The first pass we get nspell via GetLastSpell() fails in ExecuteScript! + // The second pass we get nSpell via the variable "AI_BUFF_SPELL". + int nSpell = GetLocalInt(oTarget, "AI_BUFF_SPELL"); + if(nSpell == 0) nSpell = GetLastSpell(); + // If this is a harful spell or The caster does not equal our saving PC then + // we need to fix the targets scripts back and run the correct OnSpellCastAt script. + if(GetLastSpellHarmful() || oPC != oCaster) + { + string sScript = GetLocalString(oTarget, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + ExecuteScript(sScript, oTarget); + return; + } + // If the oTarget != oCaster then we are casting a spell on one of our + // associates. We must make a second pass to get the correct information. + // We do this by saving the Target, Caster, and Spell so we can get them + // in the second pass as Execute Script makes them impossible to get on a + // second pass. + if(oTarget != oCaster) + { + SetLocalObject(oPC, "AI_BUFF_TARGET", oTarget); + SetLocalObject(oPC, "AI_BUFF_CASTER", oCaster); + SetLocalInt(oPC, "AI_BUFF_SPELL", nSpell); + ExecuteScript("pc_savebuffs", oPC); + return; + } + // If this is the first pass and we get here then oCaster is casting a spell + // on themselves. So oTarget will be invalid and we should use oPC. + // If this is the second pass and we get here then we have saved oTarget + // to oPC and this will get them so we can save the target to the spell! + oTarget = GetLocalObject(oPC, "AI_BUFF_TARGET"); + if(oTarget == OBJECT_INVALID) oTarget = oPC; + // We need to clean up this mess! + DeleteLocalObject(oPC, "AI_BUFF_TARGET"); + DeleteLocalObject(oPC, "AI_BUFF_CASTER"); + DeleteLocalInt(oPC, "AI_BUFF_SPELL"); + // This blocks one spell from saving multiple times due to being an AOE. + if(GetLocalInt(oPC, "AI_ONLY_ONE")) return; + SetLocalInt(oPC, "AI_ONLY_ONE", TRUE); + // We delay this for just less than half a round due to haste. + DelayCommand(2.5, DeleteLocalInt(oPC, "AI_ONLY_ONE")); + // Here is the whole problem and why we must do a second pass if the target + // is not the caster. These only work if this script is run by the caster. + int nClass = GetLastSpellCastClass(); + int nLevel = GetLastSpellLevel(); + // Everything below saves the spell to the database with all our now correct info. + int nDomain = GetHasDomainSpell(oPC, nClass, nLevel, nSpell); + int nMetaMagic = GetMetaMagicFeat(); + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(nDomain) sName += " [Domain]"; + if(nMetaMagic > 0 && StringToInt(Get2DAString("classes", "MemorizesSpells", nClass))) + { + // We must add the level of the metamagic to the spells level to get the spells correct level. + if(nMetaMagic == METAMAGIC_EMPOWER) { sName += " (Empowered)"; nLevel += 2; } + else if(nMetaMagic == METAMAGIC_EXTEND) { sName += " (Extended)"; nLevel += 1; } + else if(nMetaMagic == METAMAGIC_MAXIMIZE) { sName += " (Maximized)"; nLevel += 3; } + else if(nMetaMagic == METAMAGIC_QUICKEN) { sName += " (Quickened)"; nLevel += 4; } + else if(nMetaMagic == METAMAGIC_SILENT) { sName += " (Silent)"; nLevel += 1; } + else if(nMetaMagic == METAMAGIC_STILL) { sName += " (Still)"; nLevel += 1; } + } + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + string sList = JsonGetString(JsonArrayGet(jMenuData, 0)); + json jSpells = GetBuffDatabaseJson(oPC, "spells", sList); + json jSpell = JsonArray(); + jSpell = JsonArrayInsert(jSpell, JsonInt(nSpell)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nClass)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nMetaMagic)); + jSpell = JsonArrayInsert(jSpell, JsonInt(nDomain)); + string sTargetName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget, TRUE))); + jSpell = JsonArrayInsert(jSpell, JsonString(sTargetName)); + jSpell = JsonArrayInsert(jSpells, jSpell); + SetBuffDatabaseJson(oPC, "spells", jSpells, sList); + SendMessageToPC(oPC, sName + " has been saved for fast buffing on " + sTargetName + "."); + ExecuteScript("pi_buffing", oPC); +} +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if (SqlStep (sql)) return SqlGetString (sql, 0); + else return ""; +} +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@data", sData); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + SqlStep (sql); +} +void SetBuffDatabaseJson (object oPlayer, string sDataField, json jData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindJson (sql, "@data", jData); + SqlBindString (sql, "@name", sName); + SqlBindString (sql, "@tag", sTag); + SqlStep (sql); +} +json GetBuffDatabaseJson (object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString (sql, "@name", sName); + SqlBindString (sql, "@tag", sTag); + if (SqlStep (sql)) return SqlGetJson (sql, 0); + else return JsonArray (); +} +int GetHasDomainSpell(object oCaster, int nClass, int nLevel, int nSpell) +{ + int nIndex, nMaxIndex, nMSpell, nMmSpell, bDomain, nSubRadSpell, nSubSpell; + string sSubRadSpell; + if(StringToInt(Get2DAString("classes", "MemorizesSpells", nClass))) + { + nMaxIndex = GetMemorizedSpellCountByLevel(oCaster, nClass, nLevel); + while(nIndex < nMaxIndex) + { + nMSpell = GetMemorizedSpellId(oCaster, nClass, nLevel, nIndex); + if(nSpell == nMSpell) + { + if(GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex)) return nLevel; + } + nIndex ++; + } + } + return 0; +} diff --git a/src/module/nss/pe_buffing.nss b/src/module/nss/pe_buffing.nss new file mode 100644 index 0000000..a6c4050 --- /dev/null +++ b/src/module/nss/pe_buffing.nss @@ -0,0 +1,534 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pe_buffing +//////////////////////////////////////////////////////////////////////////////// + Used with pi_buffing to run the buffing plugin for + Philos Single Player Enhancements. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" + +const int BUFF_MAX_SPELLS = 50; +const string FB_NO_MONSTER_CHECK = "FB_NO_MONSTER_CHECK"; + +// sDataField should be one of the data fields for that table. +// sData is the string data to be saved. +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag); +// sDataField should be one of the data fields for that table. +// jData is the json data to be saved. +void SetBuffDatabaseJson(object oPlayer, string sDataField, json jData, string sTag); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +json GetBuffDatabaseJson(object oPlayer, string sDataField, string sTag); +// Casts all buff spells saved to the widget button. +void CastSavedBuffSpells(object oPC); +// Will check and make sure the spell is memorized and/or ready. +// Returns TRUE if memorized and ready, FALSE if memorized but not ready, +// and -1 if not memorized for classes that memorize. +// nSpell is the spell to find. +// nClass that cast the spell. +// nLevel the level of the spell. +// nMetamagic is if it has metamagic on it. +// nDomain is if it is a domain spell. +int GetSpellReady(object oCaster, int nSpell, int nClass, int nLevel, int nMetamagic, int nDomain); +// Creates the Buffing widget. +void PopupWidgetBuffGUIPanel(object oPC); +void main() +{ + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + string sWndId = NuiGetWindowId (oPC, nToken); + //************************************************************************** + // Watch to see if the window moves and save. + if(sElem == "window_geometry" && sEvent == "watch") + { + if(!GetLocalInt (oPC, AI_NO_NUI_SAVE)) + { + // Get the height, width, x, and y of the window. + json jGeom = NuiGetBind(oPC, nToken, "window_geometry"); + // Save on the player using the sWndId. + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + if(sWndId == "plbuffwin") + { + jMenuData = JsonArraySet(jMenuData, 1, JsonObjectGet(jGeom, "x")); + jMenuData = JsonArraySet(jMenuData, 2, JsonObjectGet(jGeom, "y")); + } + else if(sWndId == "widgetbuffwin") + { + jMenuData = JsonArraySet(jMenuData, 5, JsonObjectGet(jGeom, "x")); + jMenuData = JsonArraySet(jMenuData, 6, JsonObjectGet(jGeom, "y")); + } + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + } + return; + } + //************************************************************************** + // Spell Buffing. + if(sWndId == "plbuffwin") + { + if(sEvent == "click") + { + string sList; + if(GetStringLeft(sElem, 10) == "btn_spell_") + { + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + sList = JsonGetString(JsonArrayGet(jMenuData, 0)); + json jSpells = GetBuffDatabaseJson(oPC, "spells", sList); + int nIndex = StringToInt(GetStringRight(sElem, GetStringLength(sElem) - 10)); + int nSpell = JsonGetInt(JsonArrayGet(JsonArrayGet(jSpells, nIndex), 0)); + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + jSpells = JsonArrayDel(jSpells, nIndex); + SetBuffDatabaseJson(oPC, "spells", jSpells, sList); + ai_SendMessages(sName + " has been removed from the list.", AI_COLOR_YELLOW, oPC); + ExecuteScript("pi_buffing", oPC); + } + else if(sElem == "btn_save") + { + string sScript; + object oCreature; + if(JsonGetInt(NuiGetBind (oPC, nToken, "btn_save"))) + { + sScript = GetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + SetLocalObject(oPC, "AI_BUFF_PC", oPC); + SetLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT", sScript); + SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "pc_savebuffs"); + // Setup your followers to allow spells to be saved on them as well. + int nAssociateType = 2; + object oAssociate = GetAssociate(nAssociateType, oPC); + while(nAssociateType < 5) + { + if(oAssociate != OBJECT_INVALID) + { + SetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT", sScript); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "pc_savebuffs"); + } + oAssociate = GetAssociate(++nAssociateType, oPC); + } + int nIndex = 1; + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(nIndex <= AI_MAX_HENCHMAN) + { + if(oAssociate != OBJECT_INVALID) + { + SetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT", sScript); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "pc_savebuffs"); + } + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + ai_SendMessages("Cast spells on yourself or an associate to save them to the widget.", AI_COLOR_YELLOW, oPC); + } + else + { + DeleteLocalObject(oPC, "AI_BUFF_PC"); + sScript = GetLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT"); + // Cleanup your followers to allow spells to be reacted to as normal. + int nAssociateType = 2; + object oAssociate = GetAssociate(nAssociateType, oPC); + while(nAssociateType < 5) + { + if(oAssociate != OBJECT_INVALID) + { + sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + } + oAssociate = GetAssociate(++nAssociateType, oPC); + } + int nIndex = 1; + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(nIndex <= AI_MAX_HENCHMAN) + { + if(oAssociate != OBJECT_INVALID) + { + sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + } + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + NuiSetBind(oPC, nToken, "btn_save", JsonBool(FALSE)); + ai_SendMessages("Saving spells to the list has been turned off.", AI_COLOR_YELLOW, oPC); + } + } + else if(sElem == "btn_clear") + { + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + sList = JsonGetString(JsonArrayGet(jMenuData, 0)); + SetBuffDatabaseJson(oPC, "spells", JsonArray(), sList); + ExecuteScript("pi_buffing", oPC); + } + else if(sElem == "btn_buff") CastSavedBuffSpells(oPC); + // Runs all the List 1-4 buttons. + if(GetStringLeft(sElem, 8) == "btn_list") + { + sList = "list" + GetStringRight(sElem, 1); + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + jMenuData = JsonArraySet(jMenuData, 0, JsonString(sList)); + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + ExecuteScript("pi_buffing", oPC); + } + } + else if(sEvent == "watch") + { + if(sElem == "buff_widget_check") + { + int bBuffWidget = JsonGetInt(NuiGetBind(oPC, nToken, "buff_widget_check")); + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + jMenuData = JsonArraySet(jMenuData, 3, JsonBool(bBuffWidget)); + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + if(bBuffWidget) PopupWidgetBuffGUIPanel(oPC); + else NuiDestroy(oPC, NuiFindWindow(oPC, "widgetbuffwin")); + } + if(sElem == "lock_buff_widget_check") + { + int bBuffLockWidget = JsonGetInt(NuiGetBind(oPC, nToken, "lock_buff_widget_check")); + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + if(bBuffLockWidget) jMenuData = JsonArraySet(jMenuData, 3, JsonBool(TRUE)); + jMenuData = JsonArraySet(jMenuData, 4, JsonBool(bBuffLockWidget)); + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + NuiSetBind(oPC, nToken, "buff_widget_check", JsonBool(TRUE)); + PopupWidgetBuffGUIPanel(oPC); + } + if(sElem == "chbx_no_monster_check_check") + { + int bNoCheckMonsters = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetLocalInt(oPC, FB_NO_MONSTER_CHECK, bNoCheckMonsters); + } + } + } + //************************************************************************** + // Spell Buffing. + else if(sWndId == "widgetbuffwin") + { + if(sEvent == "click") + { + string sList; + if(sElem == "btn_one") sList = "list1"; + if(sElem == "btn_two") sList = "list2"; + if(sElem == "btn_three") sList = "list3"; + if(sElem == "btn_four") sList = "list4"; + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + jMenuData = JsonArraySet(jMenuData, 0, JsonString(sList)); + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + CastSavedBuffSpells(oPC); + } + } +} +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@data", sData); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + SqlStep (sql); +} +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if (SqlStep (sql)) return SqlGetString (sql, 0); + else return ""; +} +void SetBuffDatabaseJson (object oPlayer, string sDataField, json jData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindJson (sql, "@data", jData); + SqlBindString (sql, "@name", sName); + SqlBindString (sql, "@tag", sTag); + SqlStep (sql); +} +json GetBuffDatabaseJson (object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if(SqlStep(sql)) return SqlGetJson(sql, 0); + else return JsonArray(); +} +void CastBuffSpell (object oPC, object oTarget, int nSpell, int nClass, int nMetamagic, int nDomain, string sList, string sName) +{ + string sTargetName; + if(oPC == oTarget) sTargetName = "myself."; + else sTargetName = GetName(oTarget); + ai_SendMessages("Quick Buffing: " + sName + " on " + sTargetName, AI_COLOR_GREEN, oPC); + AssignCommand(oPC, ActionCastSpellAtObject(nSpell, oTarget, nMetamagic, FALSE, nDomain, 0, TRUE, nClass)); +} +void CastSavedBuffSpells(object oPC) +{ + // Lets make sure the save button is off! + if(GetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT) == "pc_savebuffs") + { + string sScript = GetLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT"); + // Cleanup your followers to allow spells to be reacted to as normal. + int nAssociateType = 2; + object oAssociate = GetAssociate(nAssociateType, oPC); + while(nAssociateType < 5) + { + if(oAssociate != OBJECT_INVALID) + { + sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + } + oAssociate = GetAssociate(++nAssociateType, oPC); + } + int nIndex = 1; + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(nIndex <= AI_MAX_HENCHMAN) + { + if(oAssociate != OBJECT_INVALID) + { + sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT"); + } + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + int nMainWindow = NuiFindWindow(oPC, "plbuffwin"); + if(nMainWindow) NuiSetBind(oPC, nMainWindow, "btn_save", JsonBool(FALSE)); + ai_SendMessages("Saving spells to the list has been turned off.", AI_COLOR_YELLOW, oPC); + } + float fDistance; + if(!GetLocalInt(oPC, FB_NO_MONSTER_CHECK)) + { + // Check for monsters! We cannot let them buff if they are close to the enemy! + object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC); + fDistance = GetDistanceBetween(oPC, oEnemy); + } + if(fDistance > 30.0f || fDistance == 0.0) + { + string sName; + float fDelay = 0.1f; + int nSpell, nClass, nLevel, nMetamagic, nDomain, nSpellReady, nIndex = 0; + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + string sList = JsonGetString(JsonArrayGet(jMenuData, 0)); + json jSpell, jSpells = GetBuffDatabaseJson(oPC, "spells", sList); + while(nIndex <= BUFF_MAX_SPELLS) + { + jSpell = JsonArrayGet(jSpells, nIndex); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nLevel = JsonGetInt(JsonArrayGet(jSpell, 2)); + nMetamagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + // We save the target's name then look them up by it. + string sTargetName = JsonGetString(JsonArrayGet(jSpell, 5)); + object oTarget; + location lLocation = GetLocation(oPC); + if(sTargetName == "" || sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName (oPC)))) oTarget = oPC; + else + { + oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 10.0, lLocation, TRUE); + while(oTarget != OBJECT_INVALID) + { + if(sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget)))) break; + oTarget = GetNextObjectInShape(SHAPE_SPHERE, 10.0, lLocation, TRUE); + } + } + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + if(oTarget == OBJECT_INVALID) + { + DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because the " + sTargetName + " is not here!", AI_COLOR_RED, oPC)); + } + else + { + if(nMetamagic > 0) + { + if(nMetamagic == METAMAGIC_EMPOWER) sName += " (Empowered)"; + else if(nMetamagic == METAMAGIC_EXTEND) sName += " (Extended)"; + else if(nMetamagic == METAMAGIC_MAXIMIZE) sName += " (Maximized)"; + else if(nMetamagic == METAMAGIC_QUICKEN) sName += " (Quickened)"; + else if(nMetamagic == METAMAGIC_SILENT) sName += " (Silent)"; + else if(nMetamagic == METAMAGIC_STILL) sName += " (Still)"; + } + nSpellReady = GetSpellReady(oPC, nSpell, nClass, nLevel, nMetamagic, nDomain); + if(nSpellReady == TRUE) + { + DelayCommand(fDelay, CastBuffSpell(oPC, oTarget, nSpell, nClass, nMetamagic, nDomain, sList, sName)); + } + else if(nSpellReady == -1) + { + DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because it is not ready to cast!", AI_COLOR_RED, oPC)); + } + else if(nSpellReady == -2) + { + DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because it is not memorized!", AI_COLOR_RED, oPC)); + } + else if(nSpellReady == -3) + { + DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because there are no spell slots of that level left!", AI_COLOR_RED, oPC)); + } + else if(nSpellReady == -4) + { + DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because that spell is not known.", AI_COLOR_RED, oPC)); + } + fDelay += 0.1f; + } + } + else break; + nIndex ++; + } + if(nIndex == 0 && !NuiFindWindow(oPC, "plbuffwin")) ExecuteScript("pi_buffing", oPC); + } + else ai_SendMessages("Enemies are too close for you to cast all your buff spells!", AI_COLOR_RED, oPC); +} +int GetSpellReady(object oCaster, int nSpell, int nClass, int nLevel, int nMetamagic, int nDomain) +{ + int nIndex, nMaxIndex, nMSpell, nMmSpell, nDSpell, nSubRadSpell, nSubSpell; + string sSubRadSpell; + if(StringToInt(Get2DAString("classes", "MemorizesSpells", nClass))) + { + int nSpellMemorized; + while(nIndex < nMaxIndex) + { + nMSpell = GetMemorizedSpellId(oCaster, nClass, nLevel, nIndex); + if(nSpell == nMSpell) + { + nMmSpell = GetMemorizedSpellMetaMagic(oCaster, nClass, nLevel, nIndex); + nDSpell = GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex); + //ai_Debug("pe_buffing", "308", "nMmSpell: " + IntToString(nMmSpell) + + // " nMetamagic: " + IntToString(nMetamagic) + + // " nDomain: " + IntToString(nDomain) + + // " nDSpell: " + IntToString(nDSpell)); + // Cannot save the domain status so we just use the first spell ID. + // Then return the domain statusl. + //if(nMmSpell == nMetamagic && + // ((nDomain > 0 && nDSpell == TRUE) || nDomain == 0 && nDSpell == FALSE)) + if(nMmSpell == nMetamagic) + { + nSpellMemorized = TRUE; + if(GetMemorizedSpellReady(oCaster, nClass, nLevel, nIndex)) + { + if(nDSpell == nDomain) return TRUE; + } + } + } + for(nSubRadSpell = 1; nSubRadSpell < 5; nSubRadSpell++) + { + sSubRadSpell = "SubRadSpell" + IntToString(nSubRadSpell); + if(nSpell == StringToInt(Get2DAString("spells", sSubRadSpell, nMSpell))) + nMmSpell = GetMemorizedSpellMetaMagic(oCaster, nClass, nLevel, nIndex); + nDSpell = GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex); + ai_Debug("pe_buffing", "421", "nMmSpell: " + IntToString(nMmSpell) + + " nMetamagic: " + IntToString(nMetamagic) + + " nDomain: " + IntToString(nDomain) + + " nDSpell: " + IntToString(nDSpell)); + if(nMmSpell == nMetamagic) + { + nSpellMemorized = TRUE; + if(GetMemorizedSpellReady(oCaster, nClass, nLevel, nIndex)) + { + if(nDSpell == nDomain) return TRUE; + } + } + } + nIndex ++; + } + if(nSpellMemorized) return -1; + return -2; + } + else + { + int nSpellKnown; + nMaxIndex = GetKnownSpellCount(oCaster, nClass, nLevel); + while(nIndex < nMaxIndex) + { + nMSpell = GetKnownSpellId(oCaster, nClass, nLevel, nIndex); + if(nSpell == nMSpell) + { + nSpellKnown = TRUE; + if(GetSpellUsesLeft(oCaster, nClass, nSpell)) return TRUE; + } + for(nSubRadSpell = 1; nSubRadSpell < 5; nSubRadSpell++) + { + sSubRadSpell = "SubRadSpell" + IntToString(nSubRadSpell); + if(nSpell == StringToInt(Get2DAString("spells", sSubRadSpell, nMSpell))) + { + nSpellKnown = TRUE; + if(GetSpellUsesLeft(oCaster, nClass, nSpell)) return TRUE; + } + } + nIndex ++; + } + if(nSpellKnown) return -3; + return -4; + } + return -2; +} +void PopupWidgetBuffGUIPanel(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // Row 1 (buttons)********************************************************** + + json jRow = CreateButtonImage(JsonArray(), "ir_level1", "btn_one", 35.0f, 35.0f, 0.0); + jRow = CreateButtonImage(jRow, "ir_level2", "btn_two", 35.0f, 35.0f, 0.0); + jRow = CreateButtonImage(jRow, "ir_level3", "btn_three", 35.0f, 35.0f, 0.0); + jRow = CreateButtonImage(jRow, "ir_level4", "btn_four", 35.0f, 35.0f, 0.0); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + int bAIBuffWidgetLock = JsonGetInt(JsonArrayGet(jMenuData, 4)); + // Get the window location to restore it from the database. + float fX = JsonGetFloat(JsonArrayGet(jMenuData, 5)); + float fY = JsonGetFloat(JsonArrayGet(jMenuData, 6)); + if(fX == 0.0f && fY == 0.0f) + { + fX = 10.0f; + fY = 10.0f; + } + float fGUI_Scale = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0; + if(bAIBuffWidgetLock) + { + fX += 4.0f; + // GUI scales are a mess, I just figured them out per scale to keep the widget from moving. + if(fGUI_Scale == 1.0) fY += 37.0; + else if(fGUI_Scale == 1.1) fY += 38.0; + else if(fGUI_Scale == 1.2) fY += 40.0; + else if(fGUI_Scale == 1.3) fY += 42.0; + else if(fGUI_Scale == 1.4) fY += 43.0; + else if(fGUI_Scale == 1.5) fY += 45.0; + else if(fGUI_Scale == 1.6) fY += 47.0; + else if(fGUI_Scale == 1.7) fY += 48.0; + else if(fGUI_Scale == 1.8) fY += 50.0; + else if(fGUI_Scale == 1.9) fY += 52.0; + else if(fGUI_Scale == 2.0) fY += 54.0; + } + // Set the layout of the window. + json jLayout = NuiCol(jCol); + int nToken; + if(bAIBuffWidgetLock) nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_buffing"); + else nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_buffing"); + // Set event watches for window inspector and save window location. + NuiSetBindWatch (oPC, nToken, "collapsed", TRUE); + NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE); + // Set the buttons to show events. + //NuiSetBind (oPC, nToken, "btn_one", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_one_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_two", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_two_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_three", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_three_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_four", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_four_event", JsonBool (TRUE)); +} + diff --git a/src/module/nss/pe_crafting.nss b/src/module/nss/pe_crafting.nss new file mode 100644 index 0000000..388c86a --- /dev/null +++ b/src/module/nss/pe_crafting.nss @@ -0,0 +1,2153 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pe_crafting +//////////////////////////////////////////////////////////////////////////////// + Used with pi_crafting to run the crafting plugin events for + Philos Single Player Enhancements. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "nw_inc_gff" +#include "0i_main" +#include "0i_items" +// Maximum model number for all items except weapons. +const int CRAFT_MAX_MODEL_NUMBER = 999; + +struct stWeaponAppearance +{ + object oItem; + int nModel; + int nColor; + string sPart; +}; +// Maximum model number for weapons. Note this will be the 100s and 10s places. +// The color number uses the ones place. Thus 25 is actually 250. +const int CRAFT_MAX_WEAPON_MODEL_NUMBER = 99; +const string CRAFT_JSON = "CRAFT_JSON"; +const string CRAFT_ORIGINAL_ITEM = "CRAFT_ORIGINAL_ITEM"; +const string CRAFT_COOL_DOWN = "CRAFT_COOL_DOWN"; +const string CRAFT_ITEM_SELECTION = "CRAFT_ITEM_SELECTION"; +const string CRAFT_MATERIAL_SELECTION = "CRAFT_MATERIAL_SELECTION"; +const string CRAFT_MODEL_SELECTION = "CRAFT_MODEL_SELECTION"; +const string CRAFT_MODEL_SPECIAL = "CRAFT_MODEL_SPECIAL"; +const string CRAFT_ITEM_TYPE = "CRAFT_ITEM_TYPE"; +const string CRAFT_WEAPON_MOD_TOP = "CRAFT_WEAPON_MOD_TOP"; +const string CRAFT_WEAPON_MOD_MID = "CRAFT_WEAPON_MOD_MID"; +const string CRAFT_WEAPON_MOD_BOT = "CRAFT_WEAPON_MOD_BOT"; +const string CRAFT_WEAPON_COL_TOP = "CRAFT_WEAPON_COL_TOP"; +const string CRAFT_WEAPON_COL_MID = "CRAFT_WEAPON_COL_MID"; +const string CRAFT_WEAPON_COL_BOT = "CRAFT_WEAPON_COL_BOT"; +const string CRAFT_COPY_ITEM = "CRAFT_COPY_ITEM"; +const string CRAFT_COPY_ITEM_TYPE = "CRAFT_COPY_ITEM_TYPE"; +const string CRAFT_COPY_MODEL = "CRAFT_COPY_MODEL"; +const string CRAFT_COPY_COLOR = "CRAFT_COPY_COLOR"; +const string CRAFT_COPY_PART_COLOR = "CRAFT_COPY_PART_COLOR"; +const string CRAFT_ARMOR_AC = "CRAFT_ARMOR_AC"; +const string CRAFT_COLOR_PALLET = "CRAFT_COLOR_PALLET"; +const string CRAFT_LEFT_PART_COLOR = "CRAFT_LEFT_PART_COLOR"; +const string CRAFT_ALL_COLOR = "CRAFT_ALL_COLOR"; +const string CRAFT_RIGHT_PART_COLOR = "CRAFT_RIGHT_PART_COLOR"; +const string CRAFT_TARGET = "CRAFT_TARGET"; +// Tag used in lighting effects. +const string CRAFT_HIGHLIGHT = "CRAFT_HIGHLIGHT"; +const string CRAFT_ULTRALIGHT = "CRAFT_ULTRALIGHT"; +// The tags for containers used to do some crafting. +const string CRAFT_TEMPLATE = "x3_plc_basket"; +const string CRAFT_CONTAINER = "CRAFT_CONTAINER"; +// Used in the crafting GUI to copy an item to be pasted to another item later. +void CopyCraftingItem(object oPC, object oItem); +// Used in the crafting GUI to paste a copy of an item to another item. +object PasteCraftingItem(object oPC, object oTarget, object oItem); +int GetItemSelectedEquipSlot(int nItemSelected); +int GetArmorModelSelected(object oPC); +object ChangeItemsAppearance(object oPC, object oTarget, int nToken, object oItem, int nDirection, string sPart); +// Checks to see if the item can be crafted. +// bPasteCheck is a special check when an item is being pasted. +int CanCraftItem(object oPC, object oItem, int nToken, int bPasteCheck = FALSE); +object RandomizeItemsCraftAppearance(object oPlayer, object oTarget, int nToken, object oItem); +// Returns the correct item based on the crafting menu selected item. +object GetSelectedItem(object oTarget, int nItemSelected); +// Cancels the crafted item for the player and restoring the original. +void CancelCraftedItem(object oPlayer, object oTarget); +// Gets the colorId from a image of the color pallet. +// Thanks Zunath for the base code. +int GetColorPalletId(object oPC, int nToken); +// Sets the pointer based on current Item, Part, and Material selected. +void SetColorPalletPointer(object oPC, int nToken, object oItem); +// Locks/Unlocks specific buttons when an item has been changed. +void LockItemInCraftingWindow(object oPC, object oItem, object oTarget, int nToken); +// Locks/Unlocks specific buttons when an item has been cleared. +void ClearItemInCraftingWindow(object oPC, object oItem, int nToken); +// Saves the crafted item for the player removing the original. +void SaveCraftedItem(object oPC, object oTarget, int nToken); +// Remove Effect of type specified from oCreature; +// sEffectTag is the tag of the effect to remove. +// Feat, Class, Racial. +void RemoveTagedEffects(object oCreature, string sEffectTag); +// Returns TRUE/FALSE if item has temporary item property. +int CheckForTemporaryItemProperty(object oItem); +// Updates the model number text in the NUI menu. +void SetModelNumberText(object oPC, object oTarget, int nToken); +// Sets the material buttons for use. +// nMaterial 0,1 Cloth 2,3 Leather 4,5 Metal -1 None. +void SetMaterialButtons(object oPC, int nToken, int nMaterial); +// Creates the item editing menu. +void CreateItemGUIPanel(object oPC, object oTarget); +// Events for ItemGUIPanel +void CraftItemInfoEvents(object oPC, int nToken); +// Creates the save/load menu for items. +//void CreateDresserGUIPanel(object oPC, object oTarget); + +int GetColorIDChange(object oItem, int nType, int nIndex, int nChange) +{ + int nColorId = GetItemAppearance(oItem, nType, nIndex) + nChange; + if(nColorId > 175) return 0; + if(nColorId < 0) return 175; + return nColorId; +} +void main() +{ + // Get the last player to use targeting mode + object oPC = GetLastPlayerToSelectTarget(); + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + if(oPC == OBJECT_SELF && sTargetMode != "") + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + //vector vTarget = GetTargetingModeSelectedPosition(); + //location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + //object oObject = GetLocalObject(oPC, "AI_TARGET_OBJECT"); + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget))// && vTarget == Vector()) + { + return; + } + // Targeting code here. + if(sTargetMode == "SELECT_TARGET") + { + if(GetAssociateType(oTarget) == ASSOCIATE_TYPE_HENCHMAN || + ai_GetIsCharacter(oTarget)) + { + SetLocalObject(oPC, CRAFT_TARGET, oTarget); + AttachCamera(oPC, oTarget); + ExecuteScript("pi_crafting", oPC); + } + else ai_SendMessages(GetName(oTarget) + " is not the player or a henchmen! Other associates cannot use item crafting.", AI_COLOR_RED, oPC); + } + DeleteLocalString(oPC, AI_TARGET_MODE); + } + else + { + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sWndId = NuiGetWindowId (oPC, nToken); + if(sWndId == "craft_item_nui") + { + CraftItemInfoEvents(oPC, nToken); + return; + } + string sEvent = NuiGetEventType(); + // We don't use and it causes error windows to go off! Return early! + if(sEvent == "mouseup") return; + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + //SendMessageToPC(oPC, "0e_crafting, 144, sElem: " + sElem + " sEvent: " + sEvent); + //************************************************************************** + // Watch to see if the window moves and save. + if(sElem == "window_geometry" && sEvent == "watch") + { + if(!GetLocalInt (oPC, AI_NO_NUI_SAVE)) + { + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + if(JsonGetType(jCraft) == JSON_TYPE_NULL) jCraft = JsonObject(); + // Get the height, width, x, and y of the window. + json jGeometry = NuiGetBind(oPC, nToken, "window_geometry"); + jCraft = JsonObjectSet(jCraft, "CRAFT_MENU", jGeometry); + SetLocalJson(oPC, CRAFT_JSON, jCraft); + } + return; + } + //************************************************************************** + object oTarget = GetLocalObject(oPC, CRAFT_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oPC; + // Get the item we are crafting. + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetSelectedItem(oTarget, nItemSelected); + object oOriginalItem = GetLocalObject(oPC, CRAFT_ORIGINAL_ITEM); + if(oItem == OBJECT_INVALID) + { + if(sElem != "btn_cancel") + { + ai_SendMessages("The item we are adjusting is not equiped!", AI_COLOR_RED, oPC); + return; + } + } + else if(oOriginalItem != OBJECT_INVALID && GetTag(oItem) != GetTag(oOriginalItem)) + { + ai_SendMessages(GetName(oItem) + " is not the item you have been adjusting!", AI_COLOR_RED, oPC); + return; + } + // Changing the name needs to be before the cooldown. + if(sElem == "txt_item_name" && sEvent == "watch") + { + string sName = JsonGetString(NuiGetBind(oPC, nToken, "txt_item_name")); + SetName(oItem, sName); + int nToken2 = NuiFindWindow(oPC, "craft_item_nui"); + if(nToken2) NuiSetBind(oPC, nToken2, "txt_item_name", JsonString(sName)); + return; + } + // Delay crafting so it has time to equip and unequip as well as remove. + //if(GetLocalInt(oPC, CRAFT_COOL_DOWN)) return; + //SetLocalInt(oPC, CRAFT_COOL_DOWN, TRUE); + //DelayCommand(0.25f, DeleteLocalInt(oPC, CRAFT_COOL_DOWN)); + // They have selected a color. + if(sElem == "color_pallet") + { + int nColorId, nChange; + object oNewItem; + if(sEvent == "mousedown") + { + // Get the color they selected from the color pallet cell. + nColorId = GetColorPalletId(oPC, nToken); + } + else if(sEvent == "mousescroll") + { + float nMouseScroll = JsonGetFloat(JsonObjectGet(JsonObjectGet(NuiGetEventPayload(), "mouse_scroll"), "y")); + nChange = FloatToInt(nMouseScroll); + } + else return; + if(!CanCraftItem(oPC, oItem, nToken)) return; + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + int nBaseItemType = GetBaseItemType(oItem); + int nAllColor = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ALL_COLOR)); + if(!nAllColor && nBaseItemType == BASE_ITEM_ARMOR) + { + int nIndex; + int nModelSelected = GetArmorModelSelected(oPC); + int nLeftColor = JsonGetInt(JsonObjectGet(jCraft, CRAFT_LEFT_PART_COLOR)); + int nRightColor = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)); + if(nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + if(nChange) nColorId = GetColorIDChange(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nChange); + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nColorId, TRUE); + DestroyObject(oItem); + } + else + { + if(nRightColor) + { + // Color Right side. + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + if(nChange) nColorId = GetColorIDChange(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nChange); + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nColorId, TRUE); + DestroyObject(oItem); + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(TRUE)); + if(nLeftColor) + { + // If we are doing the left side then add one to get the left side. + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected = nModelSelected - 1; + else nModelSelected = nModelSelected + 1; + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + if(nChange) nColorId = GetColorIDChange(oNewItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nChange); + oItem = CopyItemAndModify(oNewItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nColorId, TRUE); + DestroyObject(oNewItem); + oNewItem = oItem; + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(TRUE)); + } + } + else if(nLeftColor) + { + // If we are doing the left side then add one to get the left side. + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected = nModelSelected - 1; + else nModelSelected = nModelSelected + 1; + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + if(nChange) nColorId = GetColorIDChange(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nChange); + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, nColorId, TRUE); + DestroyObject(oItem); + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(TRUE)); + } + } + } + else + { + if(nChange) nColorId = GetColorIDChange(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected, nChange); + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected, nColorId, TRUE); + DestroyObject(oItem); + } + // Lock the new item so they can't change it on the character. + LockItemInCraftingWindow(oPC, oNewItem, oTarget, nToken); + // Equip new item. + if(nBaseItemType == BASE_ITEM_CLOAK) AssignCommand (oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CLOAK)); + else if(nBaseItemType == BASE_ITEM_HELMET) AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_HEAD)); + else if(nBaseItemType == BASE_ITEM_ARMOR) AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + } + else if(sEvent == "watch") + { + // The player is changing the item they are crafting. + if(sElem == "item_combo_selected") + { + int nSelected = JsonGetInt(NuiGetBind (oPC, nToken, sElem)); + oItem = GetSelectedItem(oTarget, nSelected); + if(oItem == OBJECT_INVALID) + { + ai_SendMessages("There is not an item to modify!", AI_COLOR_RED, oPC); + int nItem = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + NuiSetBind(oPC, nToken, "item_combo_selected", JsonInt(nItem)); + return; + } + jCraft = JsonObjectSet(jCraft, CRAFT_ITEM_SELECTION, JsonInt(nSelected)); + // Set button for cloak and helms. + if(nSelected == 1 || nSelected == 2) + { + int nHidden = GetHiddenWhenEquipped(oItem); + if(nHidden) jCraft = JsonObjectSet(jCraft, CRAFT_MODEL_SELECTION, JsonInt(1)); + else jCraft = JsonObjectSet(jCraft, CRAFT_MODEL_SELECTION, JsonInt(0)); + } + else jCraft = JsonObjectSet(jCraft, CRAFT_MODEL_SELECTION, JsonInt(0)); + SetLocalJson(oPC, CRAFT_JSON, jCraft); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_crafting", oPC); + } + // They have selected a part to change. + else if(sElem == "model_combo_selected") + { + int nSelected = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + jCraft = JsonObjectSet(jCraft, CRAFT_MODEL_SELECTION, JsonInt(nSelected)); + SetLocalJson(oPC, CRAFT_JSON, jCraft); + SetModelNumberText(oPC, oTarget, nToken); + int nItem = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + if(nItem == 1) // Cloak + { + if(!CanCraftItem(oPC, oItem, nToken)) return; + object oItem = GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget); + if(nSelected == 1) SetHiddenWhenEquipped(oItem, TRUE); + else SetHiddenWhenEquipped(oItem, FALSE); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + else if(nItem == 2) // Headgear + { + if(!CanCraftItem(oPC, oItem, nToken)) return; + object oItem = GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget); + if(nSelected == 1) SetHiddenWhenEquipped(oItem, TRUE); + else SetHiddenWhenEquipped(oItem, FALSE); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + else if(nItem == 4 && ai_GetIsShield(oItem)) + { + if(!CanCraftItem(oPC, oItem, nToken)) return; + object oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget); + if(nSelected == 1) SetHiddenWhenEquipped(oItem, TRUE); + else SetHiddenWhenEquipped(oItem, FALSE); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + if(ai_GetIsWeapon(oItem)) + { + // Clearing sets the module to 0 triggering an extra call. + if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + if(!CanCraftItem(oPC, oItem, nToken)) return; + int nVisual; + itemproperty ipProperty = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ipProperty)) + { + if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_VISUALEFFECT) + { + RemoveItemProperty(oItem, ipProperty); + } + ipProperty = GetNextItemProperty(oItem); + } + if(nSelected == 1) nVisual = ITEM_VISUAL_ACID; + else if(nSelected == 2) nVisual = ITEM_VISUAL_COLD; + else if(nSelected == 3) nVisual = ITEM_VISUAL_ELECTRICAL; + else if(nSelected == 4) nVisual = ITEM_VISUAL_EVIL; + else if(nSelected == 5) nVisual = ITEM_VISUAL_FIRE; + else if(nSelected == 6) nVisual = ITEM_VISUAL_HOLY; + else if(nSelected == 7) nVisual = ITEM_VISUAL_SONIC; + if(nVisual) + { + ipProperty = ItemPropertyVisualEffect(nVisual); + AddItemProperty(DURATION_TYPE_PERMANENT, ipProperty, oItem); + } + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + } + } + else if(sEvent == "click") + { + if(sElem == "btn_info") + { + SetLocalObject(oPC, "CRAFT_INFO_ITEM", oItem); + CreateItemGUIPanel(oPC, oItem); + } + //else if(sElem == "btn_wardrobe") CreateDresserGUIPanel(oPC, oTarget); + // Random button to change items looks randomly. + else if(sElem == "btn_randomize") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + oItem = RandomizeItemsCraftAppearance(oPC, oTarget, nToken, oItem); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + } + // Save any changes made to the selected item. + else if(sElem == "btn_save") + { + SaveCraftedItem(oPC, oTarget, nToken); + } + // Selecte target to change clothing on. + else if(sElem == "btn_select_target") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_crafting"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "SELECT_TARGET"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select either your charcter or a henchman to craft their equipment.", AI_COLOR_YELLOW, oPC); + DeleteLocalObject(oPC, CRAFT_ORIGINAL_ITEM); + DeleteLocalObject(oPC, CRAFT_TARGET); + DeleteLocalObject(oPC, "CRAFT_INFO_ITEM"); + if(GetLocalInt(oPC, CRAFT_ULTRALIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_ULTRALIGHT); + DeleteLocalInt(oPC, CRAFT_ULTRALIGHT); + } + if(GetLocalInt(oPC, CRAFT_HIGHLIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_HIGHLIGHT); + DeleteLocalInt(oPC, CRAFT_HIGHLIGHT); + } + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + // Cancel any changes made to the selected item. + else if(sElem == "btn_cancel") + { + // If the button is on cancel then clear the item. + if(JsonGetString(NuiGetBind(oPC, nToken, "btn_cancel_label")) == "Cancel") + { + CancelCraftedItem(oPC, oTarget); + ClearItemInCraftingWindow(oPC, oItem, nToken); + DelayCommand(0.5, NuiDestroy(oPC, nToken)); + DelayCommand(0.5, ExecuteScript("pi_crafting", oPC)); + } + // If the button is on Exit not Cancel then exit. + else + { + AssignCommand(oPC, RestoreCameraFacing()); + AttachCamera(oPC, oPC); + DeleteLocalObject(oPC, CRAFT_ORIGINAL_ITEM); + DeleteLocalObject(oPC, CRAFT_TARGET); + DeleteLocalObject(oPC, "CRAFT_INFO_ITEM"); + NuiDestroy(oPC, nToken); + nToken = NuiFindWindow(oPC, "craft_item_nui"); + if(nToken) NuiDestroy(oPC, nToken); + if(GetLocalInt(oPC, CRAFT_ULTRALIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_ULTRALIGHT); + DeleteLocalInt(oPC, CRAFT_ULTRALIGHT); + } + if(GetLocalInt(oPC, CRAFT_HIGHLIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_HIGHLIGHT); + DeleteLocalInt(oPC, CRAFT_HIGHLIGHT); + } + } + } + // Get the previous model of the selected item. + else if(GetStringLeft(sElem, 9) == "btn_prev_") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + oItem = ChangeItemsAppearance(oPC, oTarget, nToken, oItem, -1, GetStringRight(sElem, 1)); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + } + // Get the next model of the selected item. + else if(GetStringLeft(sElem, 9) == "btn_next_") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + oItem = ChangeItemsAppearance(oPC, oTarget, nToken, oItem, 1, GetStringRight(sElem, 1)); + LockItemInCraftingWindow(oPC, oItem, oTarget, nToken); + } + } + else if(sElem == "btn_highlight") + { + if(GetLocalInt(oPC, CRAFT_HIGHLIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_HIGHLIGHT); + DeleteLocalInt(oPC, CRAFT_HIGHLIGHT); + NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(FALSE)); + } + else + { + if(GetLocalInt(oPC, CRAFT_ULTRALIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_ULTRALIGHT); + DeleteLocalInt(oPC, CRAFT_ULTRALIGHT); + } + SetLocalInt(oPC, CRAFT_HIGHLIGHT, TRUE); + effect eLight = EffectVisualEffect(VFX_DUR_LIGHT_WHITE_20); + eLight = TagEffect(eLight, CRAFT_HIGHLIGHT); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLight, oTarget); + NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(TRUE)); + } + } + else if(sElem == "btn_left_part_color") + { + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(TRUE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(FALSE)); + SetColorPalletPointer(oPC, nToken, oItem); + } + else if(sElem == "btn_all_color") + { + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(TRUE)); + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(FALSE)); + SetColorPalletPointer(oPC, nToken, oItem); + } + else if(sElem == "btn_right_part_color") + { + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(TRUE)); + SetColorPalletPointer(oPC, nToken, oItem); + } + else if(sElem == "btn_right_part_reset") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + int nIndex; + int nModelSelected = GetArmorModelSelected(oPC); + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + object oNewItem; + if(nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, 255, TRUE); + DestroyObject(oItem); + } + else + { + nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, 255, TRUE); + DestroyObject(oItem); + } + // Lock the new item so they can't change it on the character. + LockItemInCraftingWindow(oPC, oNewItem, oTarget, nToken); + // Equip new item. + AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(FALSE)); + int nLeft = JsonGetInt(NuiGetBind(oPC, nToken, "btn_left_part_color")); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(!nLeft)); + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(!nLeft)); + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + nLeft = JsonGetInt(NuiGetBind(oPC, nToken, "btn_left_part_reset_event")); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nLeft)); + SetColorPalletPointer(oPC, nToken, oNewItem); + } + } + else if(sElem == "btn_all_reset") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + int nIndex, nColor; + json jItem = ObjectToJson(oItem, TRUE); + string sColor, sPartName; + for(nIndex = 0;nIndex < 19;nIndex++) + { + sPartName = "APart_" + IntToString(nIndex) + "_Col_"; + for(nColor = 0;nColor < 6;nColor++) + { + sColor = IntToString(nColor); + if(JsonGetType(GffGetByte(jItem, sPartName + sColor)) != JSON_TYPE_NULL) + { + jItem = GffRemoveByte(jItem, sPartName + sColor); + } + } + } + object oNewItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + DestroyObject(oItem); + // Lock the new item so they can't change it on the character. + LockItemInCraftingWindow(oPC, oNewItem, oTarget, nToken); + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(TRUE)); + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonInt(FALSE)); + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + SetColorPalletPointer(oPC, nToken, oNewItem); + } + } + else if(sElem == "btn_left_part_reset") + { + if(CanCraftItem(oPC, oItem, nToken)) + { + int nModelSelected = GetArmorModelSelected(oPC); + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected = nModelSelected - 1; + else nModelSelected = nModelSelected + 1; + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + int nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + object oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex, 255, TRUE); + DestroyObject(oItem); + // Lock the new item so they can't change it on the character. + LockItemInCraftingWindow(oPC, oNewItem, oTarget, nToken); + // Equip new item. + AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + // Fix buttons. + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonInt(FALSE)); + int nRight = JsonGetInt(NuiGetBind(oPC, nToken, "btn_right_part_color")); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(!nRight)); + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonInt(!nRight)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + nRight = JsonGetInt(NuiGetBind(oPC, nToken, "btn_right_part_reset_event")); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nRight)); + SetColorPalletPointer(oPC, nToken, oNewItem); + } + } + // They have changed the material (color item) for the item. + else if(GetStringLeft(sElem, 13) == "btn_material_") + { + int nSelected = StringToInt(GetStringRight(sElem, 1)); + SetMaterialButtons(oPC, nToken, nSelected); + jCraft = JsonObjectSet(jCraft, CRAFT_MATERIAL_SELECTION, JsonInt(nSelected)); + // Change the pallet for the correct material. + string sColorPallet; + if(nSelected < 4) + { + sColorPallet = "gui_pal_tattoo"; + NuiSetBind(oPC, nToken, "armor_block_1", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "armor_block_2", JsonBool(FALSE)); + } + else + { + sColorPallet = "armor_pallet"; + if(ResManGetAliasFor(sColorPallet, RESTYPE_TGA) == "") + { + sColorPallet = "gui_pal_tattoo"; + NuiSetBind(oPC, nToken, "armor_block_1", JsonBool(TRUE)); + } + } + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString (sColorPallet)); + SetLocalString(oPC, CRAFT_COLOR_PALLET, sColorPallet); + SetColorPalletPointer(oPC, nToken, oItem); + } + SetLocalJson(oPC, CRAFT_JSON, jCraft); + } + else if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + AssignCommand(oPC, PlaySound("gui_button")); + if(sElem == "btn_highlight") + { + if(GetLocalInt(oPC, CRAFT_ULTRALIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_ULTRALIGHT); + DeleteLocalInt(oPC, CRAFT_ULTRALIGHT); + NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(FALSE)); + } + else + { + if(GetLocalInt(oPC, CRAFT_HIGHLIGHT)) + { + RemoveTagedEffects(oTarget, CRAFT_HIGHLIGHT); + DeleteLocalInt(oPC, CRAFT_HIGHLIGHT); + } + SetLocalInt(oPC, CRAFT_ULTRALIGHT, TRUE); + effect eLight = EffectVisualEffect(VFX_DUR_ULTRAVISION); + eLight = TagEffect(eLight, CRAFT_ULTRALIGHT); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLight, oTarget); + NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(TRUE)); + } + } + } + } + } +} +/*void CopyCraftingItem(object oPC, object oItem) +{ + //ai_Debug("pe_crafting", "295", JsonDump(ObjectToJson(oItem), 2)); + json jItem = ObjectToJson(oItem); + + SetLocalInt(oPC, CRAFT_COPY_ITEM, TRUE); + int nSelected = GetLocalInt(oPC, CRAFT_ITEM_SELECTION); + if (ai_GetIsWeapon(oItem)) + { + // Copy the base item type; + SetLocalInt(oPC, CRAFT_COPY_ITEM_TYPE, GetBaseItemType(oItem)); + // Copy each model/color & save to variables. + int nIndex = 1; + string sIndex; + while(nIndex <= 3) + { + sIndex = IntToString(nIndex); + SetLocalInt(oPC, CRAFT_COPY_MODEL + sIndex, JsonGetInt(GffGetByte(jItem, "ModelPart" + sIndex))); + nIndex++; + } + } + else if (nSelected == 0) + { + // Copy the armors AC so we can check it. + SetLocalInt(oPC, CRAFT_ARMOR_AC, ai_GetArmorBonus(oItem)); + // Copy an per part colors if they exist. + int nPart, nColor, nPartColor; + string sPart, sColor; + while(nPart <= 18) + { + sPart = IntToString(nPart); + nColor = 0; + while(nColor <= 5) + { + sColor = IntToString(nColor); + if(GffGetFieldExists(jItem, "APart_" + sPart + "_Col_" + sColor, GFF_FIELD_TYPE_BYTE)) + { + // Shift the number up by 1 so we can save as a variable and not use 0! + nPartColor = JsonGetInt(GffGetByte(jItem, "APart_" + sPart + "_Col_" + sColor)) + 1; + SetLocalInt(oPC, CRAFT_COPY_PART_COLOR + sPart + sColor, nPartColor); + } + nColor++; + } + nPart++; + } + // Copy each model & save to variables. + SetLocalInt(oPC, "CRAFT_COPY_MODEL0", JsonGetInt(GffGetByte(jItem, "ArmorPart_Belt"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL1", JsonGetInt(GffGetByte(jItem, "ArmorPart_LBicep"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL2", JsonGetInt(GffGetByte(jItem, "ArmorPart_LFArm"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL3", JsonGetInt(GffGetByte(jItem, "ArmorPart_LFoot"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL4", JsonGetInt(GffGetByte(jItem, "ArmorPart_LHand"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL5", JsonGetInt(GffGetByte(jItem, "ArmorPart_LShin"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL6", JsonGetInt(GffGetByte(jItem, "ArmorPart_LShoul"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL7", JsonGetInt(GffGetByte(jItem, "ArmorPart_LThigh"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL8", JsonGetInt(GffGetByte(jItem, "ArmorPart_Neck"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL9", JsonGetInt(GffGetByte(jItem, "ArmorPart_Pelvis"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL10", JsonGetInt(GffGetByte(jItem, "ArmorPart_RBicep"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL11", JsonGetInt(GffGetByte(jItem, "ArmorPart_RFArm"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL12", JsonGetInt(GffGetByte(jItem, "ArmorPart_RFoot"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL13", JsonGetInt(GffGetByte(jItem, "ArmorPart_RHand"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL14", JsonGetInt(GffGetByte(jItem, "ArmorPart_RShin"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL15", JsonGetInt(GffGetByte(jItem, "ArmorPart_RShoul"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL16", JsonGetInt(GffGetByte(jItem, "ArmorPart_RThigh"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL17", JsonGetInt(GffGetByte(jItem, "ArmorPart_Robe"))); + SetLocalInt(oPC, "CRAFT_COPY_MODEL18", JsonGetInt(GffGetByte(jItem, "ArmorPart_Torso"))); + // Copy each color and save to variables. + SetLocalInt(oPC, "CRAFT_COPY_COLOR0", JsonGetInt(GffGetByte(jItem, "Cloth1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR1", JsonGetInt(GffGetByte(jItem, "Cloth2Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR2", JsonGetInt(GffGetByte(jItem, "Leather1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR3", JsonGetInt(GffGetByte(jItem, "Leather2Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR4", JsonGetInt(GffGetByte(jItem, "Metal1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR5", JsonGetInt(GffGetByte(jItem, "Metal2Color"))); + } +else + { + // Copy the base item type; + SetLocalInt(oPC, CRAFT_COPY_ITEM_TYPE, GetBaseItemType(oItem)); + // Copy the base item type; + SetLocalInt(oPC, "CRAFT_COPY_MODEL0", JsonGetInt(GffGetByte(jItem, "ModelPart1"))); + // Copy each color and save to variables. + SetLocalInt(oPC, "CRAFT_COPY_COLOR0", JsonGetInt(GffGetByte(jItem, "Cloth1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR1", JsonGetInt(GffGetByte(jItem, "Cloth2Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR2", JsonGetInt(GffGetByte(jItem, "Leather1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR3", JsonGetInt(GffGetByte(jItem, "Leather2Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR4", JsonGetInt(GffGetByte(jItem, "Metal1Color"))); + SetLocalInt(oPC, "CRAFT_COPY_COLOR5", JsonGetInt(GffGetByte(jItem, "Metal2Color"))); + } + // Send message that it has been copied. + ai_SendMessages(GetName (oItem) + " appearance has been copied!", AI_COLOR_GREEN, oPC); +} + +// Used in the crafting GUI to paste a copy of an item to another item. +object PasteCraftingItem (object oPC, object oTarget, object oItem) +{ + int nModelPartNum; + object oChestItem; + int nSelected = GetLocalInt(oPC, CRAFT_ITEM_SELECTION); + object oBuildContainer = GetObjectByTag(CRAFT_CONTAINER); + // Move the item to the building container. + oChestItem = CopyItem(oItem, oBuildContainer, TRUE); + DestroyObject(oItem); + json jItem = ObjectToJson(oChestItem, TRUE); + if (ai_GetIsWeapon(oChestItem)) + { + // Copy each model & save to variables. + int nIndex = 1; + string sIndex; + while(nIndex <= 3) + { + sIndex = IntToString(nIndex); + jItem = GffReplaceByte(jItem,"ModelPart" + sIndex, GetLocalInt(oPC, CRAFT_COPY_MODEL + sIndex)); + jItem = GffReplaceWord(jItem,"xModelPart" + sIndex, GetLocalInt(oPC, CRAFT_COPY_MODEL + sIndex)); + DeleteLocalInt(oPC, CRAFT_COPY_MODEL + sIndex); + nIndex++; + } + oItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + // Equip new item. + AssignCommand(oTarget, ActionEquipItem (oItem, INVENTORY_SLOT_RIGHTHAND)); + } + // Armor. + else if (nSelected == 0) + { + // Paste per part colors if they exist. + int nPart, nColor, nPartColor; + string sPart, sColor; + while(nPart <= 18) + { + sPart = IntToString(nPart); + nColor = 0; + while(nColor <= 5) + { + sColor = IntToString(nColor); + nPartColor = GetLocalInt(oPC, CRAFT_COPY_PART_COLOR + sPart + sColor); + if(nPartColor > 0) + { + // Shift the number down by 1 since we can not use 0 in the variable! + nPartColor = nPartColor - 1; + if(GffGetFieldExists(jItem, "APart_" + sPart + "_Col_" + sColor, GFF_FIELD_TYPE_BYTE)) + { + jItem = GffReplaceByte(jItem, "APart_" + sPart + "_Col_" + sColor, nPartColor); + } + else jItem = GffAddByte(jItem, "APart_" + sPart + "_Col_" + sColor, nPartColor); + DeleteLocalInt(oPC, "CRAFT_COPY_PART_COLOR" + sPart + sColor); + } + nColor++; + } + nPart++; + } + jItem = GffReplaceByte(jItem,"ArmorPart_Belt", GetLocalInt(oPC, "CRAFT_COPY_MODEL0")); + jItem = GffReplaceByte(jItem,"ArmorPart_LBicep", GetLocalInt(oPC, "CRAFT_COPY_MODEL1")); + jItem = GffReplaceByte(jItem,"ArmorPart_LFArm", GetLocalInt(oPC, "CRAFT_COPY_MODEL2")); + jItem = GffReplaceByte(jItem,"ArmorPart_LFoot", GetLocalInt(oPC, "CRAFT_COPY_MODEL3")); + jItem = GffReplaceByte(jItem,"ArmorPart_LHand", GetLocalInt(oPC, "CRAFT_COPY_MODEL4")); + jItem = GffReplaceByte(jItem,"ArmorPart_LShin", GetLocalInt(oPC, "CRAFT_COPY_MODEL5")); + jItem = GffReplaceByte(jItem,"ArmorPart_LShoul", GetLocalInt(oPC, "CRAFT_COPY_MODEL6")); + jItem = GffReplaceByte(jItem,"ArmorPart_LThigh", GetLocalInt(oPC, "CRAFT_COPY_MODEL7")); + jItem = GffReplaceByte(jItem,"ArmorPart_Neck", GetLocalInt(oPC, "CRAFT_COPY_MODEL8")); + jItem = GffReplaceByte(jItem,"ArmorPart_Pelvis", GetLocalInt(oPC, "CRAFT_COPY_MODEL9")); + jItem = GffReplaceByte(jItem,"ArmorPart_RBicep", GetLocalInt(oPC, "CRAFT_COPY_MODEL10")); + jItem = GffReplaceByte(jItem,"ArmorPart_RFArm", GetLocalInt(oPC, "CRAFT_COPY_MODEL11")); + jItem = GffReplaceByte(jItem,"ArmorPart_RFoot", GetLocalInt(oPC, "CRAFT_COPY_MODEL12")); + jItem = GffReplaceByte(jItem,"ArmorPart_RHand", GetLocalInt(oPC, "CRAFT_COPY_MODEL13")); + jItem = GffReplaceByte(jItem,"ArmorPart_RShin", GetLocalInt(oPC, "CRAFT_COPY_MODEL14")); + jItem = GffReplaceByte(jItem,"ArmorPart_RShoul", GetLocalInt(oPC, "CRAFT_COPY_MODEL15")); + jItem = GffReplaceByte(jItem,"ArmorPart_RThigh", GetLocalInt(oPC, "CRAFT_COPY_MODEL16")); + jItem = GffReplaceByte(jItem,"ArmorPart_Robe", GetLocalInt(oPC, "CRAFT_COPY_MODEL17")); + jItem = GffReplaceByte(jItem,"ArmorPart_Torso", GetLocalInt(oPC, "CRAFT_COPY_MODEL18")); + jItem = GffReplaceWord(jItem,"xArmorPart_Belt", GetLocalInt(oPC, "CRAFT_COPY_MODEL0")); + jItem = GffReplaceWord(jItem,"xArmorPart_LBice", GetLocalInt(oPC, "CRAFT_COPY_MODEL1")); + jItem = GffReplaceWord(jItem,"xArmorPart_LFArm", GetLocalInt(oPC, "CRAFT_COPY_MODEL2")); + jItem = GffReplaceWord(jItem,"xArmorPart_LFoot", GetLocalInt(oPC, "CRAFT_COPY_MODEL3")); + jItem = GffReplaceWord(jItem,"xArmorPart_LHand", GetLocalInt(oPC, "CRAFT_COPY_MODEL4")); + jItem = GffReplaceWord(jItem,"xArmorPart_LShin", GetLocalInt(oPC, "CRAFT_COPY_MODEL5")); + jItem = GffReplaceWord(jItem,"xArmorPart_LShou", GetLocalInt(oPC, "CRAFT_COPY_MODEL6")); + jItem = GffReplaceWord(jItem,"xArmorPart_LThig", GetLocalInt(oPC, "CRAFT_COPY_MODEL7")); + jItem = GffReplaceWord(jItem,"xArmorPart_Neck", GetLocalInt(oPC, "CRAFT_COPY_MODEL8")); + jItem = GffReplaceWord(jItem,"xArmorPart_Pelvi", GetLocalInt(oPC, "CRAFT_COPY_MODEL9")); + jItem = GffReplaceWord(jItem,"xArmorPart_RBice", GetLocalInt(oPC, "CRAFT_COPY_MODEL10")); + jItem = GffReplaceWord(jItem,"xArmorPart_RFArm", GetLocalInt(oPC, "CRAFT_COPY_MODEL11")); + jItem = GffReplaceWord(jItem,"xArmorPart_RFoot", GetLocalInt(oPC, "CRAFT_COPY_MODEL12")); + jItem = GffReplaceWord(jItem,"xArmorPart_RHand", GetLocalInt(oPC, "CRAFT_COPY_MODEL13")); + jItem = GffReplaceWord(jItem,"xArmorPart_RShin", GetLocalInt(oPC, "CRAFT_COPY_MODEL14")); + jItem = GffReplaceWord(jItem,"xArmorPart_RShou", GetLocalInt(oPC, "CRAFT_COPY_MODEL15")); + jItem = GffReplaceWord(jItem,"xArmorPart_RThig", GetLocalInt(oPC, "CRAFT_COPY_MODEL16")); + jItem = GffReplaceWord(jItem,"xArmorPart_Robe", GetLocalInt(oPC, "CRAFT_COPY_MODEL17")); + jItem = GffReplaceWord(jItem,"xArmorPart_Torso", GetLocalInt(oPC, "CRAFT_COPY_MODEL18")); + jItem = GffReplaceByte(jItem,"Cloth1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR0")); + jItem = GffReplaceByte(jItem,"Cloth2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR1")); + jItem = GffReplaceByte(jItem,"Leather1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR2")); + jItem = GffReplaceByte(jItem,"Leather2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR3")); + jItem = GffReplaceByte(jItem,"Metal1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR4")); + jItem = GffReplaceByte(jItem,"Metal2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR5")); + oItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + int nIndex; + for(nIndex = 0; nIndex <= 18; nIndex++) + { + DeleteLocalInt(oPC, CRAFT_COPY_MODEL + IntToString(nIndex)); + } + for(nIndex = 0; nIndex <= 5; nIndex++) + { + DeleteLocalInt(oPC, CRAFT_COPY_COLOR + IntToString(nIndex)); + } + // Equip new item. + AssignCommand (oTarget, ActionEquipItem (oItem, INVENTORY_SLOT_CHEST)); + } + else if(ai_GetIsShield(oChestItem)) + { + jItem = GffReplaceByte(jItem,"ModelPart1", GetLocalInt(oPC, "CRAFT_COPY_MODEL1")); + jItem = GffReplaceWord(jItem,"xModelPart1", GetLocalInt(oPC, "CRAFT_COPY_MODEL1")); + oItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + // Equip new item. + AssignCommand(oTarget, ActionEquipItem (oItem, INVENTORY_SLOT_LEFTHAND)); + } + else + { + //ai_Debug("pe_crafting", "389", JsonDump(ObjectToJson(oChestItem), 2)); + jItem = GffReplaceByte(jItem,"ModelPart1", GetLocalInt(oPC, "CRAFT_COPY_MODEL0")); + jItem = GffReplaceWord(jItem,"xModelPart1", GetLocalInt(oPC, "CRAFT_COPY_MODEL0")); + jItem = GffReplaceByte(jItem,"Cloth1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR0")); + jItem = GffReplaceByte(jItem,"Cloth2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR1")); + jItem = GffReplaceByte(jItem,"Leather1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR2")); + jItem = GffReplaceByte(jItem,"Leather2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR3")); + jItem = GffReplaceByte(jItem,"Metal1Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR4")); + jItem = GffReplaceByte(jItem,"Metal2Color", GetLocalInt(oPC, "CRAFT_COPY_COLOR5")); + oItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + DeleteLocalInt(oPC, "CRAFT_COPY_MODEL0"); + int nIndex; + for(nIndex = 0; nIndex <= 5; nIndex++) + { + DeleteLocalInt(oPC, CRAFT_COPY_COLOR + IntToString(nIndex)); + } + // Equip new item. + int nItemType = GetBaseItemType(oChestItem); + if(nItemType == BASE_ITEM_CLOAK) AssignCommand(oTarget, ActionEquipItem (oItem, INVENTORY_SLOT_CLOAK)); + else if(nItemType == BASE_ITEM_HELMET) AssignCommand(oTarget, ActionEquipItem (oItem, INVENTORY_SLOT_HEAD)); + } + // Send message that it has been copied. + AssignCommand(oPC, ai_SendMessages (GetName (oItem) + " appearance has been changed!", AI_COLOR_GREEN, oPC)); + DestroyObject(oChestItem); + return oItem; +} */ +int GetItemSelectedEquipSlot (int nItemSelected) +{ + if (nItemSelected == 0) return INVENTORY_SLOT_CHEST; + if (nItemSelected == 1) return INVENTORY_SLOT_CLOAK; + if (nItemSelected == 2) return INVENTORY_SLOT_HEAD; + if (nItemSelected == 3) return INVENTORY_SLOT_RIGHTHAND; + if (nItemSelected == 4) return INVENTORY_SLOT_LEFTHAND; + return INVENTORY_SLOT_CHEST; +} +int GetArmorModelSelected (object oPC) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nModelSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION)); + if(nModelSelected == 0) return ITEM_APPR_ARMOR_MODEL_NECK; + if(nModelSelected == 1) return ITEM_APPR_ARMOR_MODEL_RSHOULDER; + if(nModelSelected == 2) return ITEM_APPR_ARMOR_MODEL_RBICEP; + if(nModelSelected == 3) return ITEM_APPR_ARMOR_MODEL_RFOREARM; + if(nModelSelected == 4) return ITEM_APPR_ARMOR_MODEL_RHAND; + if(nModelSelected == 5) return ITEM_APPR_ARMOR_MODEL_TORSO; + if(nModelSelected == 6) return ITEM_APPR_ARMOR_MODEL_BELT; + if(nModelSelected == 7) return ITEM_APPR_ARMOR_MODEL_PELVIS; + if(nModelSelected == 8) return ITEM_APPR_ARMOR_MODEL_RTHIGH; + if(nModelSelected == 9) return ITEM_APPR_ARMOR_MODEL_RSHIN; + if(nModelSelected == 10) return ITEM_APPR_ARMOR_MODEL_RFOOT; + return ITEM_APPR_ARMOR_MODEL_ROBE; +} +int GetMaxSimpleItemNumber(object oItem, int nBaseItemType) +{ + int nResType, nMaxNumber, nModelNumber; + string sModelNumber, sModelName = Get2DAString("baseitems", "ItemClass", nBaseItemType) + "_"; + //ai_Debug("pe_crafting", "804", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + while(nModelNumber < 999) + { + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + if(nBaseItemType == BASE_ITEM_CLOAK) nResType = RESTYPE_PLT; + else nResType = RESTYPE_MDL; + if(ResManGetAliasFor(sModelName + sModelNumber, nResType) != "") nMaxNumber++; + nModelNumber++; + //ai_Debug("pe_crafting", "841", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + } + return nMaxNumber; +} +int GetSimpleItemNumber(object oItem, int nModelNumber, int nBaseItemType) +{ + int nResType, nIndex, nCounter; + string sModelNumber, sModelName = Get2DAString("baseitems", "ItemClass", nBaseItemType) + "_"; + //ai_Debug("pe_crafting", "804", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + while(nIndex <= 999) + { + if(nIndex < 10) sModelNumber = "00" + IntToString(nIndex); + else if(nIndex < 100) sModelNumber = "0" + IntToString(nIndex); + else sModelNumber = IntToString(nIndex); + if(nBaseItemType == BASE_ITEM_CLOAK) nResType = RESTYPE_PLT; + else nResType = RESTYPE_MDL; + if(ResManGetAliasFor(sModelName + sModelNumber, nResType) != "") nCounter++; + if(nCounter == nModelNumber) return nIndex; + nIndex++; + //ai_Debug("pe_crafting", "841", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + } + return nIndex; +} +int GetMaxWeaponModuleNumber(struct stWeaponAppearance stWA) +{ + int nBaseItemType = GetBaseItemType(stWA.oItem); + stWA.nColor = 1; + stWA.nModel = 99; + stWA.sPart = "t"; + string sModelNumber; + string sModelName = Get2DAString("baseitems", "ItemClass", nBaseItemType) + "_" + stWA.sPart + "_"; + int nModelNumber = (stWA.nModel * 10) + stWA.nColor; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //SendMessageToPC(GetFirstPC(), "pe_crafting, 780, sModel: " + sModelName + sModelNumber + + // " nModel: " + IntToString(stWA.nModel) + " nColor: " + IntToString(stWA.nColor)); + while(ResManGetAliasFor(sModelName + sModelNumber, RESTYPE_MDL) == "") + { + stWA.nModel += -1; + // Create the model name. + nModelNumber = (stWA.nModel * 10) + stWA.nColor; + if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //SendMessageToPC(GetFirstPC(), "pe_crafting, 789, sModel: " + sModelName + sModelNumber + + // " nModel: " + IntToString(stWA.nModel) + " nColor: " + IntToString(stWA.nColor)); + } + return stWA.nModel; +} +struct stWeaponAppearance GetNextWeaponAppearance(struct stWeaponAppearance stWA, int nDirection) +{ + int nBaseItemType = GetBaseItemType(stWA.oItem); + string sModelNumber; + string sModelName = Get2DAString("baseitems", "ItemClass", nBaseItemType) + "_" + stWA.sPart + "_"; + // Get next/previous color/model. + stWA.nColor += nDirection; + if(stWA.nColor > 9) + { + stWA.nColor = 1; + stWA.nModel += nDirection; + if(stWA.nModel > CRAFT_MAX_WEAPON_MODEL_NUMBER) stWA.nModel = 1; + } + else if(stWA.nColor < 1) + { + stWA.nColor = 9; + stWA.nModel += nDirection; + if(stWA.nModel < 1) stWA.nModel = CRAFT_MAX_WEAPON_MODEL_NUMBER; + } + int nModelNumber = (stWA.nModel * 10) + stWA.nColor; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //SendMessageToPC(GetFirstPC(), "pe_crafting, 778, sModel: " + sModelName + sModelNumber + + // " nModel: " + IntToString(stWA.nModel) + " nColor: " + IntToString(stWA.nColor)); + while(ResManGetAliasFor(sModelName + sModelNumber, RESTYPE_MDL) == "") + { + // Get next/previous color/model. + stWA.nColor += nDirection; + if(stWA.nColor > 9) + { + stWA.nColor = 1; + stWA.nModel += nDirection; + if(stWA.nModel > CRAFT_MAX_WEAPON_MODEL_NUMBER) stWA.nModel = 1; + } + else if(stWA.nColor < 1) + { + stWA.nColor = 9; + stWA.nModel += nDirection; + if(stWA.nModel < 1) stWA.nModel = CRAFT_MAX_WEAPON_MODEL_NUMBER; + } + // Create the model name. + nModelNumber = (stWA.nModel * 10) + stWA.nColor; + if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //SendMessageToPC(GetFirstPC(), "pe_crafting, 800, sModel: " + sModelName + sModelNumber + + // " nModel: " + IntToString(stWA.nModel) + " nColor: " + IntToString(stWA.nColor)); + } + return stWA; +} +object ChangeItemsAppearance(object oPC, object oTarget, int nToken, object oItem, int nDirection, string sPart) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + // Get the item we are changing. + int nModelSelected; + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + string sModelName, sModelNumber; + object oNewItem; + // Weapons. + if(ai_GetIsWeapon(oItem)) + { + // Freeze animations - vfx 352? + if(sPart == "t") nModelSelected = 2; + else if(sPart == "m") nModelSelected = 1; + else if(sPart == "b") nModelSelected = 0; + sModelName = Get2DAString("baseitems", "ItemClass", GetBaseItemType(oItem)) + "_" + sPart + "_"; + struct stWeaponAppearance stWA; + stWA.oItem = oItem; + stWA.sPart = sPart; + stWA.nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, nModelSelected); + stWA.nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, nModelSelected); + stWA = GetNextWeaponAppearance(stWA, nDirection); + json jItem = ObjectToJson(oItem, TRUE); + int nModelNumber = stWA.nModel * 10 + stWA.nColor; + jItem = GffReplaceByte(jItem, "ModelPart" + IntToString(nModelSelected + 1), nModelNumber); + jItem = GffReplaceWord(jItem, "xModelPart" + IntToString(nModelSelected + 1), nModelNumber); + oNewItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + AssignCommand(oTarget, ClearAllActions(TRUE)); + DestroyObject(oItem); + // Item selected 3 is the right hand, 4 is the left hand. + //SendMessageToPC(oPC, "nItemSelected: " + IntToString(nItemSelected)); + if(nItemSelected == 3) + { + AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND)); + } + else AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_LEFTHAND)); + NuiSetBind(oPC, nToken, "txt_model_number_" + sPart, JsonString(IntToString(nModelNumber))); + } + // Armor. + else if(nItemSelected == 0) + { + // Create the model name. + // Get the ModelType. + int nAppearance = GetAppearanceType(oTarget); + string sModelName = Get2DAString("appearance", "MODELTYPE", nAppearance); + // Get gender. + if(GetGender(oTarget) == GENDER_MALE) sModelName += "m"; + else sModelName += "f"; + // Get race. + sModelName += Get2DAString("appearance", "RACE", nAppearance); + // Get Phenotype. + sModelName += IntToString(GetPhenoType(oTarget)) + "_"; + // Get the selected model. + nModelSelected = GetArmorModelSelected(oPC); + //ai_Debug("pe_crafting", "646", "nModelSide: " + IntToString(nModelSide)); + // If we are doing the left side (bottom menu options) then add one to + // get the left side. + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if(sPart == "b") + { + if(nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--; + else nModelSelected++; + } + int nModelNumber = StringToInt(JsonGetString(NuiGetBind(oPC, nToken, "txt_model_number_" + sPart))); + //int nModelNumber = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected); + //SendMessageToPC(oPC, "pe_crafting, 826, nModelNumber: " + IntToString(nModelNumber) + + // " sPart: " + sPart + " nModelSelected: " + IntToString(nModelSelected)); + int nBaseModelNumber = nModelNumber; + nModelNumber += nDirection; + if(nModelNumber > CRAFT_MAX_MODEL_NUMBER) nModelNumber = 0; + else if(nModelNumber < 0) nModelNumber = CRAFT_MAX_MODEL_NUMBER; + string sModelNumber; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + // Check for changes to the torso (base part of the armor linked to AC). + if(nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO) + { + string sCurrentACBonus = Get2DAString("parts_chest", "ACBONUS", nBaseModelNumber); + string sACBonus = Get2DAString ("parts_chest", "ACBONUS", nModelNumber); + sModelName += Get2DAString ("capart", "MDLNAME", nModelSelected); + //SendMessageToPC(oPC, "pe_crafting, 842, sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber) + " sCurrentACBonus: " + sCurrentACBonus + + // " sACBonus: " + sACBonus + " nModelSelected: " + IntToString(nModelSelected)); + while(ResManGetAliasFor(sModelName + sModelNumber, RESTYPE_MDL) == "" || + sACBonus != sCurrentACBonus) + { + nModelNumber += nDirection; + if (nModelNumber > CRAFT_MAX_MODEL_NUMBER) nModelNumber = 0; + else if (nModelNumber < 0) nModelNumber = CRAFT_MAX_MODEL_NUMBER; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + sACBonus = Get2DAString ("parts_chest", "ACBONUS", nModelNumber); + //SendMessageToPC(oPC, "pe_crafting, 854, sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber) + " sACBonus: " + sACBonus + + // " nModelSelected: " + IntToString(nModelSelected)); + } + // Change the model. + oNewItem = CopyItemAndModify (oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected, nModelNumber, TRUE); + DestroyObject (oItem); + AssignCommand (oTarget, ActionEquipItem (oNewItem, INVENTORY_SLOT_CHEST)); + } + // Change all other parts of armor. + else + { + sModelName += Get2DAString("capart", "MDLNAME", nModelSelected); + //SendMessageToPC(oPC, "pe_crafting, 866, sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber) + " nModelSelected: " + IntToString(nModelSelected)); + while(ResManGetAliasFor(sModelName + sModelNumber, RESTYPE_MDL) == "") + { + nModelNumber += nDirection; + if (nModelNumber > CRAFT_MAX_MODEL_NUMBER) nModelNumber = 0; + else if (nModelNumber < 0) nModelNumber = CRAFT_MAX_MODEL_NUMBER; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //SendMessageToPC(oPC, "pe_crafting, 705, sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber) + " nModelSelected: " + IntToString(nModelSelected)); + } + oNewItem = CopyItemAndModify (oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected, nModelNumber, TRUE); + DestroyObject (oItem); + // If using the linked menu option then change the left side too. + if(sPart == "m" && (nModelSelected != ITEM_APPR_ARMOR_MODEL_NECK && + nModelSelected != ITEM_APPR_ARMOR_MODEL_BELT && + nModelSelected != ITEM_APPR_ARMOR_MODEL_PELVIS && + nModelSelected != ITEM_APPR_ARMOR_MODEL_ROBE)) + { + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--; + else nModelSelected++; + oItem = CopyItemAndModify(oNewItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected, nModelNumber, TRUE); + DestroyObject(oNewItem); + AssignCommand(oTarget, ActionEquipItem(oItem, INVENTORY_SLOT_CHEST)); + } + else AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + } + string sModelSelected; + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + NuiSetBind(oPC, nToken, "txt_model_number_" + sPart, JsonString(IntToString(nModelNumber))); + } + else + { + if(sPart == "m") + { + // Using labels for Mobile. + //NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(IntToString(nModelNumber))); + //NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(IntToString(nModelNumber))); + //NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(IntToString(nModelNumber))); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(IntToString(nModelNumber))); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(IntToString(nModelNumber))); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(IntToString(nModelNumber))); + } + else + { + NuiSetBind(oPC, nToken, "txt_model_number_" + sPart, JsonString(IntToString(nModelNumber))); + } + } + } + // All other items. + else + { + int nSlot, nResType, nBaseItemType = GetBaseItemType(oItem); + string sModelName = Get2DAString("baseitems", "ItemClass", nBaseItemType) + "_"; + if(nBaseItemType == BASE_ITEM_CLOAK) + { + nSlot = INVENTORY_SLOT_CLOAK; + nResType = RESTYPE_PLT; + } + else if(nBaseItemType == BASE_ITEM_HELMET) + { + nSlot = INVENTORY_SLOT_HEAD; + nResType = RESTYPE_MDL; + } + else if(nBaseItemType == BASE_ITEM_LARGESHIELD || + nBaseItemType == BASE_ITEM_SMALLSHIELD || + nBaseItemType == BASE_ITEM_TOWERSHIELD) + { + nSlot = INVENTORY_SLOT_LEFTHAND; + nResType = RESTYPE_MDL; + } + int nModelNumber = GetItemAppearance(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0); + nModelNumber += nDirection; + if (nModelNumber > CRAFT_MAX_MODEL_NUMBER) nModelNumber = 0; + else if (nModelNumber < 0) nModelNumber = CRAFT_MAX_MODEL_NUMBER; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //ai_Debug("pe_crafting", "804", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + while(ResManGetAliasFor(sModelName + sModelNumber, nResType) == "") + { + nModelNumber += nDirection; + if (nModelNumber > CRAFT_MAX_MODEL_NUMBER) nModelNumber = 0; + else if (nModelNumber < 0) nModelNumber = CRAFT_MAX_MODEL_NUMBER; + if(nModelNumber < 10) sModelNumber = "00" + IntToString(nModelNumber); + else if(nModelNumber < 100) sModelNumber = "0" + IntToString(nModelNumber); + else sModelNumber = IntToString(nModelNumber); + //ai_Debug("pe_crafting", "841", "sModelName: " + sModelName + sModelNumber + + // " nModelNumber: " + IntToString(nModelNumber)); + } + oNewItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0, nModelNumber, TRUE); + DestroyObject(oItem); + AssignCommand(oTarget, ActionEquipItem (oNewItem, nSlot)); + NuiSetBind(oPC, nToken, "txt_model_number_" + sPart, JsonString(IntToString(nModelNumber))); + } + return oNewItem; +} +object RandomizeItemsCraftAppearance(object oPC, object oTarget, int nToken, object oItem) +{ + // Get the item we are changing. + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + int nBaseItemType = GetBaseItemType(oItem); + object oNewItem; + if(ai_GetIsWeapon(oItem)) + { + int nRollTop, nRollMid, nRollBottom; + int nColorTop, nColorMid, nColorBottom; + struct stWeaponAppearance stWA; + stWA.oItem = oItem; + int nMaxModuleNumber = GetMaxWeaponModuleNumber(stWA); + nRollTop = Random(nMaxModuleNumber) + 1; + // Check bows as they must randomize to the same top, middle, and bottom otherwise they look bad. + if(nBaseItemType == BASE_ITEM_LONGBOW || nBaseItemType == BASE_ITEM_SHORTBOW) + { + nRollMid = nRollTop; + nRollBottom = nRollTop; + } + // Randomize each item individualy for other weapons. + else + { + nRollMid = Random(nMaxModuleNumber) + 1; + nRollBottom = Random(nMaxModuleNumber) + 1; + } + nColorTop = Random(9) + 1; + nColorMid = Random(9) + 1; + nColorBottom = Random(9) + 1; + // Change weapons model. + stWA.sPart = "t"; + stWA.nModel = nRollTop; + stWA.nColor = nColorTop; + stWA = GetNextWeaponAppearance(stWA, -1); + json jItem = ObjectToJson(oItem, TRUE); + //ai_Debug("pe_crafting", "614", "ModelPart" + IntToString(nModelSelected + 1) + + // " nModelNumber: " + IntToString(nModelNumber)); + jItem = GffReplaceByte(jItem, "ModelPart" + IntToString(3), stWA.nModel * 10 + stWA.nColor); + jItem = GffReplaceWord(jItem, "xModelPart" + IntToString(3), stWA.nModel * 10 + stWA.nColor); + NuiSetBind(oPC, nToken, "txt_model_number_" + stWA.sPart, JsonString(IntToString(stWA.nModel * 10 + stWA.nColor))); + stWA.sPart = "m"; + stWA.nModel = nRollMid; + stWA.nColor = nColorMid; + stWA = GetNextWeaponAppearance(stWA, -1); + jItem = GffReplaceByte(jItem, "ModelPart" + IntToString(2), stWA.nModel * 10 + stWA.nColor); + jItem = GffReplaceWord(jItem, "xModelPart" + IntToString(2), stWA.nModel * 10 + stWA.nColor); + NuiSetBind(oPC, nToken, "txt_model_number_" + stWA.sPart, JsonString(IntToString(stWA.nModel * 10 + stWA.nColor))); + stWA.sPart = "b"; + stWA.nModel = nRollBottom; + stWA.nColor = nColorBottom; + stWA = GetNextWeaponAppearance(stWA, -1); + jItem = GffReplaceByte(jItem, "ModelPart" + IntToString(1), stWA.nModel * 10 + stWA.nColor); + jItem = GffReplaceWord(jItem, "xModelPart" + IntToString(1), stWA.nModel * 10 + stWA.nColor); + NuiSetBind(oPC, nToken, "txt_model_number_" + stWA.sPart, JsonString(IntToString(stWA.nModel * 10 + stWA.nColor))); + oNewItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + AssignCommand(oTarget, ClearAllActions(TRUE)); + DestroyObject(oItem); + // Item selected 3 is the right hand, 4 is the left hand. + if (nItemSelected == 3) AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND)); + else AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_LEFTHAND)); + } + // Armor. + else if(nItemSelected == 0) + { + int nRoll, nRoll2; + json jItem = ObjectToJson(oItem, TRUE); + // Randomize the models. + // Randomize Torso + //jItem = GffReplaceByte(jItem, "ArmorPart_Torso", ); + //jItem = GffReplaceWord(jItem, "xArmorPart_Torso", ); + // Randomize the colors. + nRoll = Random(175) + 1; + if(d100() < 50) nRoll2 = nRoll + Random(5) - 3; + else nRoll2 = Random(175) + 1; + jItem = GffReplaceByte(jItem, "Cloth1Color", nRoll); + jItem = GffReplaceByte(jItem, "Cloth2Color", nRoll2); + if(d100() < 50) nRoll = nRoll + Random(5) - 3; + else nRoll = Random(175) + 1; + if(d100() < 50) nRoll2 = nRoll + Random(5) - 3; + else nRoll2 = Random(175) + 1; + jItem = GffReplaceByte(jItem, "Leather1Color", nRoll); + jItem = GffReplaceByte(jItem, "Leather2Color", nRoll2); + if(d100() < 50) nRoll = nRoll + Random(5) - 3; + else nRoll = Random(175) + 1; + if(d100() < 50) nRoll2 = nRoll + Random(5) - 3; + else nRoll2 = Random(175) + 1; + jItem = GffReplaceByte(jItem, "Metal1Color", nRoll); + jItem = GffReplaceByte(jItem, "Metal2Color", nRoll2); + DestroyObject(oItem); + oNewItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + AssignCommand(oTarget, ActionEquipItem(oNewItem, INVENTORY_SLOT_CHEST)); + } + // All other items. + else + { + int nSlot; + // Get max models and inventory slot. + int nMaxModel = GetMaxSimpleItemNumber(oItem, nBaseItemType); + if(nBaseItemType == BASE_ITEM_CLOAK) nSlot = INVENTORY_SLOT_CLOAK; + else if(nBaseItemType == BASE_ITEM_HELMET) nSlot = INVENTORY_SLOT_HEAD; + else if(nBaseItemType == BASE_ITEM_LARGESHIELD || nBaseItemType == BASE_ITEM_SMALLSHIELD || + nBaseItemType == BASE_ITEM_TOWERSHIELD) nSlot = INVENTORY_SLOT_LEFTHAND; + int nRoll = Random(nMaxModel) + 1; + int nModel = GetSimpleItemNumber(oItem, nRoll, nBaseItemType); + json jItem = ObjectToJson(oItem, TRUE); + jItem = GffReplaceByte(jItem, "ModelPart1", nModel); + jItem = GffReplaceWord(jItem, "xModelPart1", nModel); + if (nBaseItemType == BASE_ITEM_CLOAK || nBaseItemType == BASE_ITEM_HELMET) + { + jItem = GffReplaceByte(jItem, "Cloth1Color", Random(175) + 1); + jItem = GffReplaceByte(jItem, "Cloth2Color", Random(175) + 1); + jItem = GffReplaceByte(jItem, "Leather1Color", Random(175) + 1); + jItem = GffReplaceByte(jItem, "Leather2Color", Random(175) + 1); + jItem = GffReplaceByte(jItem, "Metal1Color", Random(175) + 1); + jItem = GffReplaceByte(jItem, "Metal2Color", Random(175) + 1); + } + DestroyObject(oItem); + oNewItem = JsonToObject(jItem, GetLocation(oTarget), oTarget, TRUE); + AssignCommand(oTarget, ActionEquipItem(oNewItem, nSlot)); + } + return oNewItem; +} +object GetSelectedItem(object oTarget, int nItemSelected) +{ + if(nItemSelected == 0) return GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + else if(nItemSelected == 1) return GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget); + else if(nItemSelected == 2) return GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget); + else if(nItemSelected == 3) return GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + else if(nItemSelected == 4) return GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget); + return OBJECT_INVALID; +} +void CancelCraftedItem(object oPC, object oTarget) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetSelectedItem(oTarget, nItemSelected); + object oOriginalItem = GetLocalObject(oPC, CRAFT_ORIGINAL_ITEM); + if(oOriginalItem != OBJECT_INVALID) + { + DestroyObject(oItem); + int nSlot = GetItemSelectedEquipSlot(nItemSelected); + // Give item Backup to Player + oOriginalItem = CopyItem(oOriginalItem, oTarget, TRUE); + DelayCommand(0.2f, AssignCommand (oTarget, ActionEquipItem(oOriginalItem, nSlot))); + DeleteLocalObject(oPC, CRAFT_ORIGINAL_ITEM); + } +} +// Gets the colorId from a image of the color pallet. +// Thanks Zunath for the base code. +int GetColorPalletId(object oPC, int nToken) +{ + float fScale = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0f; + json jPayload = NuiGetEventPayload(); + json jMousePosition = JsonObjectGet(jPayload, "mouse_pos"); + json jX = JsonObjectGet(jMousePosition, "x"); + json jY = JsonObjectGet(jMousePosition, "y"); + float fX = StringToFloat(JsonDump (jX)); + float fY = StringToFloat(JsonDump (jY)); + float fCellSize = 20.0f * fScale; + int nCellX = FloatToInt(fX / fCellSize); + int nCellY = FloatToInt(fY / fCellSize); + if(nCellX < 0) nCellX = 0; + else if (nCellX > 16) nCellX = 16; + if(nCellY < 0) nCellY = 0; + else if(nCellY > 11) nCellY = 11; + NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(IntToFloat(nCellX * 20), IntToFloat(nCellY * 20), 20.0, 20.0)); + return nCellX + nCellY * 16; +} +void SetColorPalletPointer(object oPC, int nToken, object oItem) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + int nColor; + if(!JsonGetInt(NuiGetBind(oPC, nToken, "btn_all_color"))) + { + int nModelSelected = GetArmorModelSelected(oPC); + if(!JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR))) + { + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--; + else nModelSelected++; + } + int nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex); + } + else nColor = 255; + if(nColor == 255) nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected); + float fPointX = IntToFloat((nColor - ((nColor / 16) * 16)) * 20); + float fPointY = IntToFloat((nColor / 16) * 20); + NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(fPointX, fPointY, 20.0, 20.0)); +} +void LockItemInCraftingWindow(object oPC, object oItem, object oTarget, int nToken) +{ + NuiSetBind(oPC, nToken, "item_combo_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_cancel_label", JsonString("Cancel")); + NuiSetBind(oPC, nToken, "btn_cancel_tooltip", JsonString(" Revert back to the original items appearance")); + NuiSetBind(oPC, nToken, "btn_save_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_select_target_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_info_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_wardrobe_event", JsonBool(FALSE)); + // Make sure the item information window is closed. + nToken = NuiFindWindow(oPC, "craft_item_nui"); + if(nToken) NuiDestroy(oPC, nToken); +} +void ClearItemInCraftingWindow(object oPC, object oItem, int nToken) +{ + NuiSetBind(oPC, nToken, "btn_save_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "item_combo_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_select_target_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_info_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_wardrobe_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cancel_label", JsonString("Exit")); + NuiSetBind(oPC, nToken, "btn_cancel_tooltip", JsonString(" Exit the crafting menu")); + if(ai_GetIsWeapon(oItem)) + { + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + NuiSetBind(oPC, nToken, "model_combo_selected", JsonInt(0)); + DelayCommand(1.0, DeleteLocalInt(oPC, AI_NO_NUI_SAVE)); + } +} +void SaveCraftedItem(object oPC, object oTarget, int nToken) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetSelectedItem(oTarget, nItemSelected); + ClearItemInCraftingWindow(oPC, oItem, nToken); + DestroyObject(GetLocalObject(oPC, CRAFT_ORIGINAL_ITEM)); + DeleteLocalObject(oPC, CRAFT_ORIGINAL_ITEM); +} +int CanCraftItem(object oPC, object oItem, int nToken, int bPasteCheck = FALSE) +{ + // Plot items cannot be changed. + if(GetPlotFlag(oItem)) + { + ai_SendMessages(GetName(oItem) + "is a plot item and its appearance cannot be changed!", AI_COLOR_RED, oPC); + return FALSE; + } + // Cannot change temorary enchanted items. + if(CheckForTemporaryItemProperty(oItem)) + { + ai_SendMessages(GetName(oItem) + " cannot be altered while it has a temporary enchantment.", AI_COLOR_RED, oPC); + return FALSE; + } + // Do special paste checks. + if (bPasteCheck) + { + int nOldItemType = GetLocalInt (oPC, CRAFT_COPY_ITEM_TYPE); + int nNewItemType = GetBaseItemType(oItem); + if(nNewItemType == BASE_ITEM_ARMOR) + { + if(GetLocalInt (oPC, CRAFT_ARMOR_AC) != ai_GetArmorBonus(oItem)) + { + ai_SendMessages("The armor you are trying to paste to is not the same type as the copy!", AI_COLOR_RED, oPC); + return FALSE; + } + } + else if(nOldItemType != nNewItemType) + { + string sOldBaseItem = GetStringByStrRef(StringToInt(Get2DAString ("baseitems", "Name", nOldItemType))); + string sNewBaseItem = GetStringByStrRef(StringToInt(Get2DAString ("baseitems", "Name", nNewItemType))); + ai_SendMessages("You copied a " + sOldBaseItem + " and are trying to paste to a " + sNewBaseItem + "!", AI_COLOR_RED, oPC); + return FALSE; + } + } + if(GetLocalObject(oPC, CRAFT_ORIGINAL_ITEM) == OBJECT_INVALID) + { + object oBuildContainer = GetObjectByTag(CRAFT_CONTAINER); + if(!GetIsObjectValid(oBuildContainer)) + { + vector vPosition = GetPositionFromLocation(GetLocation(oPC)); + vPosition.z = vPosition.z -2.0; + location lLocation = Location(GetArea(oPC), vPosition, 0.0); + oBuildContainer = CreateObject(OBJECT_TYPE_PLACEABLE, CRAFT_TEMPLATE, lLocation, FALSE, CRAFT_CONTAINER); + //SetObjectVisualTransform(oBuildContainer, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z, -5.0); + } + object oBackup = CopyItem(oItem, oBuildContainer, TRUE); + // Save the original item to the PC. + SetLocalObject(oPC, CRAFT_ORIGINAL_ITEM, oBackup); + } + return TRUE; +} +void RemoveTagedEffects(object oCreature, string sEffectTag) +{ + //Search for the effect. + //Debug ("0i_effects", "578", "RemoveTagedEffects: " + sEffectTag); + effect eEffect = GetFirstEffect(oCreature); + while (GetIsEffectValid(eEffect)) + { + //Debug ("0i_effects", "582", "Effect Tag: " + GetEffectTag (eEffect)); + if (GetEffectTag(eEffect) == sEffectTag) RemoveEffect(oCreature, eEffect); + eEffect = GetNextEffect(oCreature); + } +} +int CheckForTemporaryItemProperty (object oItem) +{ + itemproperty ipProperty; + ipProperty = GetFirstItemProperty (oItem); + while (GetIsItemPropertyValid (ipProperty)) + { + // Check to see if the item is temporary enchanted. + if (GetItemPropertyDurationType (ipProperty) == DURATION_TYPE_TEMPORARY) return TRUE; + ipProperty = GetNextItemProperty (oItem); + } + return FALSE; +} +int GetHasPartColor(object oItem, int nPart, string sSide) +{ + json jItem = ObjectToJson(oItem); + string sPartName = "APart_"; + if(sSide == "Left") + { + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nPart == ITEM_APPR_ARMOR_MODEL_RTHIGH) nPart--; + else nPart++; + } + sPartName += IntToString(nPart) + "_Col_"; + int nPartColor = JsonGetInt(GffGetByte(jItem, sPartName + "0")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "1")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "2")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "3")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "4")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "5")); + //SendMessageToPC(GetFirstPC(), "sPartName: " + sPartName + " nPartColor: " + IntToString(nPartColor)); + return nPartColor; +} +void SetModelNumberText(object oPC, object oTarget, int nToken) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nItem = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetSelectedItem(oTarget, nItem); + int nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION)); + string sModelTop, sModelMiddle, sModelBottom; + // Model Group + if (ai_GetIsWeapon (oItem)) + { + int nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 0); + int nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 0); + int nModelNumber = (nModel * 10) + nColor; + sModelTop = IntToString(nModelNumber); + nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 1); + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 1); + nModelNumber = (nModel * 10) + nColor; + sModelMiddle = IntToString(nModelNumber); + nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 2); + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 2); + nModelNumber = (nModel * 10) + nColor; + sModelBottom = IntToString(nModelNumber); + NuiSetBind(oPC, nToken, "top_title_label", JsonString("Top")); + //NuiSetBind(oPC, nToken, "txt_model_number_t_enable", JsonBool(TRUE)); + //NuiSetBindWatch(oPC, nToken, "txt_model_number_t", TRUE); + NuiSetBind(oPC, nToken, "txt_model_name_t", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Middle")); + //NuiSetBind(oPC, nToken, "txt_model_number_m_enable", JsonBool(TRUE)); + //NuiSetBindWatch(oPC, nToken, "txt_model_number_m", TRUE); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Bottom")); + //NuiSetBind(oPC, nToken, "txt_model_number_b_enable", JsonBool(TRUE)); + //NuiSetBindWatch(oPC, nToken, "txt_model_number_b", TRUE); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom)); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE)); + } + // Armor and clothing + if(nItem == 0) + { + nSelected = GetArmorModelSelected(oPC); + // These models only have one side so make sure we are not linked. + if (nSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + NuiSetBind(oPC, nToken, "top_title_label", JsonString("")); + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_name_t", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model")); + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("")); + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE)); + } + else + { + sModelTop = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + if(nSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nSelected--; + else nSelected++; + sModelBottom = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + NuiSetBind(oPC, nToken, "top_title_label", JsonString("Right")); + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Right & Left")); + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Left")); + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom)); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE)); + } + } + // Cloaks and Helmets. + else + { + sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0)); + NuiSetBind(oPC, nToken, "top_title_label", JsonString("")); + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE)); + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model")); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString("")); + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE)); + } + // Color Group + if(ai_GetIsWeapon(oItem) || ai_GetIsShield(oItem)) + { + // Need to disable the color widgets. + // Row 511 + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString("gui_pal_tattoo")); + NuiSetBind(oPC, nToken, "color_pallet_image_event", JsonBool(FALSE)); + // Row 512 - Label Part to Color + // Row 5l3 + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 515 + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + // Row 516 - Label Material to Color + // Row 517 + NuiSetBind(oPC, nToken, "btn_material_0", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_2", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_4", JsonBool(FALSE)); + // Row 518 + NuiSetBind(oPC, nToken, "btn_material_1", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_3", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_5", JsonBool(FALSE)); + SetMaterialButtons(oPC, nToken, -1); + } + // Armor and clothing + else if(nItem == 0) + { + // Row 511 + string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET); + if(sColorPallet == "") sColorPallet = "gui_pal_tattoo"; + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet)); + NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel")); + NuiSetBindWatch(oPC, nToken, "txt_color_l", TRUE); + int nSelectedRight, nSelectedAll, nSelectedLeft; + int nModelSelected = GetArmorModelSelected(oPC); + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + string sColorAll = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected)); + // These models only have one side so make sure we are not linked. + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + // Row 512 - Label Part to Color + // Row 5l3 + nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)); + nSelectedAll = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ALL_COLOR)); + if(!nSelectedRight && !nSelectedAll) + { + nSelectedAll = TRUE; + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(TRUE)); + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonBool(FALSE)); + } + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedAll = nSelectedRight; + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + } + else + { + // Row 511 + string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET); + if(sColorPallet == "") sColorPallet = "gui_pal_tattoo"; + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet)); + NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel")); + // Row 512 - Label Part to Color + // Row 5l3 + nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)); + nSelectedAll = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ALL_COLOR)); + nSelectedLeft = JsonGetInt(JsonObjectGet(jCraft, CRAFT_LEFT_PART_COLOR)); + if(!nSelectedRight && !nSelectedAll && !nSelectedLeft) + { + nSelectedAll = TRUE; + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(TRUE)); + } + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(nSelectedLeft)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(TRUE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedLeft = GetHasPartColor(oItem, nModelSelected, "Left"); + nSelectedAll = nSelectedRight || nSelectedLeft; + //SendMessageToPC(oPC, "nSelectedRight: " + IntToString(nSelectedRight) + + // " nSelectedLeft: " + IntToString(nSelectedLeft)); + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(nSelectedLeft)); + // Row 516 - Label Material to Color + // Row 517 & 518 + nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + SetMaterialButtons(oPC, nToken, nSelected); + } + SetLocalJson(oPC, CRAFT_JSON, jCraft); + } + // Cloaks and Helmets. + else + { + // Row 512 - Label Part to Color + // Row 5l3 + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + //NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE)); + // Row 516 - Label Material to Color + // Row 517 & 518 + nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + SetMaterialButtons(oPC, nToken, nSelected); + } +} +void SetMaterialButtons(object oPC, int nToken, int nMaterial) +{ + int nIndex, bBool, bUseable; + string sIndex; + if(nMaterial > -1) bUseable = TRUE; + for(nIndex = 0;nIndex < 6;nIndex++) + { + if(nIndex == nMaterial) bBool = TRUE; + else bBool = FALSE; + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_material_" + sIndex + "_event", JsonBool(bUseable)); + NuiSetBind(oPC, nToken, "btn_material_" + sIndex, JsonBool(bBool)); + } +} +void CreateItemGUIPanel(object oPC, object oItem) +{ + // Row 1 (Name)************************************************************* 73 + json jRow = CreateLabel(JsonArray(), "Name:", "lbl_name_title", 50.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateTextEditBox (jRow, "name_placeholder", "txt_item_name", 60, FALSE, 325.0f, 20.0f); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Tag)************************************************************** 101 + jRow = CreateLabel(JsonArray(), "Tag:", "lbl_tag_title", 50.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateTextEditBox(jRow, "name_placeholder", "txt_item_tag", 60, FALSE, 325.0f, 20.0f); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 2 (ResRef)*********************************************************** 129 + jRow = CreateLabel(JsonArray(), "ResRef:", "lbl_resref_title", 50.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateTextEditBox(jRow, "name_placeholder", "txt_item_resref", 60, FALSE, 325.0f, 20.0f); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Base Item/Weight)************************************************* 157 + jRow = CreateLabel(JsonArray(), "Base Item: ", "lbl_baseitem_title", 75.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "", "lbl_baseitem", 145.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "Weight: ", "lbl_weight_title", 55.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "", "lbl_weight", 65.0f, 20.0f, NUI_HALIGN_LEFT); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (Gold Value)******************************************************* 185 + jRow = CreateLabel(JsonArray(), "Gold Value: ", "lbl_gold_title", 85.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "", "lbl_gold_value", 135.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "Minimum Level: ", "lbl_min_lvl_title", 110.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateLabel(jRow, "", "lbl_min_lvl", 20.0f, 20.0f, NUI_HALIGN_LEFT); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 (Plot/Stolen)****************************************************** 213 + jRow = CreateCheckBox(JsonArray(), " Plot", "chbx_plot", 110.0, 20.0f, "chbx_plot_tooltip"); + jRow = CreateCheckBox(jRow, " Stolen", "chbx_stolen", 110.0, 20.0f, "chbx_stolen_tooltip"); + jRow = CreateCheckBox(jRow, " Cursed", "chbx_cursed", 110.0, 20.0f, "chbx_cursed_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 6 (Identified/Droppable)********************************************* 269 + jRow = CreateCheckBox(JsonArray(), " Identified", "chbx_identified", 110.0, 25.0f, "chbx_identified_tooltip"); + jRow = CreateCheckBox(jRow, " Droppable", "chbx_droppable", 110.0, 25.0f, "chbx_droppable_tooltip"); + jRow = CreateButton(jRow, "Save as UTI", "btn_save_uti", 110.0, 25.0, -1.0, "btn_save_uti_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 9 (Stack/Variables/Destroy/Charges)********************************** 307 + jRow = CreateTextEditBox(JsonArray(), "name_placeholder", "txt_stack", 4, FALSE, 35.0f, 25.0f); + jRow = CreateLabel(jRow, " Stack", "lbl_stack_title", 72.0f, 20.0f, NUI_HALIGN_LEFT); + jRow = CreateTextEditBox(jRow, "name_placeholder", "txt_charges", 4, FALSE, 40.0f, 25.0f); + jRow = CreateLabel(jRow, " Charges", "lbl_charges_title", 68.0f, 25.0f, NUI_HALIGN_LEFT); + jRow = CreateButtonSelect(jRow, "Destroy", "btn_destroy", 110.0, 25.0, "btn_destroy_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 11 (Description)***************************************************** 558 + jRow = CreateTextEditBox(JsonArray(), "desc_placeholder", "txt_desc", 1000, TRUE, 375.0, 243.0, "txt_desc_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 566.0; + // Row 12 (Item Base Description)* ***************************************** 158 + int nBaseItemType = GetBaseItemType(oItem); + float fWeight; + string sBaseItemDesc; + if(nBaseItemType == BASE_ITEM_ARMOR) + { + int nArmorAC = ai_GetArmorBonus(oItem); + sBaseItemDesc = GetStringByStrRef(StringToInt(Get2DAString("armor", "BASEITEMSTATREF", nArmorAC))); + fWeight = StringToFloat(Get2DAString("armor", "WEIGHT", nArmorAC)); + } + else + { + sBaseItemDesc = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "BaseItemStatRef", nBaseItemType))); + fWeight = StringToFloat(Get2DAString("baseitems", "TenthLBS", nBaseItemType)); + } + if(sBaseItemDesc == "Bad Strref") sBaseItemDesc = ""; + if(sBaseItemDesc != "") + { + jRow = CreateTextBox(JsonArray(), "txt_base_desc", 375.0, 150.0, FALSE, NUI_SCROLLBARS_NONE, "txt_base_desc_tooltip"); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 158.0; + } + // Set the layout of the window. + json jLayout = NuiCol (jCol); + object oOwner = GetItemPossessor(oItem); + string sName = ai_StripColorCodes (GetName(oOwner)); + int nToken = SetWindow (oPC, jLayout, "craft_item_nui", sName + "'s item menu", + -1.0, -1.0, 400.0, fHeight, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_crafting"); + // Set the buttons to show events to 0e_window. + NuiSetBind(oPC, nToken, "txt_item_name_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_item_name", JsonString(GetName(oItem))); + NuiSetBindWatch(oPC, nToken, "txt_item_name", TRUE); + NuiSetBind(oPC, nToken, "txt_item_tag_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_item_tag", JsonString(GetTag(oItem))); + NuiSetBindWatch(oPC, nToken, "txt_item_tag", TRUE); + NuiSetBind(oPC, nToken, "txt_item_resref_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_item_resref", JsonString(GetResRef(oItem))); + NuiSetBindWatch(oPC, nToken, "txt_item_resref", TRUE); + string sValue = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "Name", nBaseItemType))); + NuiSetBind(oPC, nToken, "lbl_baseitem_label", JsonString(sValue)); + sValue = FloatToString(fWeight * 0.1f, 0, 1); + NuiSetBind(oPC, nToken, "lbl_weight_label", JsonString(sValue)); + int nValue = GetGoldPieceValue(oItem); + NuiSetBind (oPC, nToken, "lbl_gold_value_label", JsonString(IntToString(nValue))); + sValue = IntToString (ai_GetMinimumEquipLevel(oItem)); + NuiSetBind(oPC, nToken, "lbl_min_lvl_label", JsonString (sValue)); + nValue = GetPlotFlag (oItem); + NuiSetBind(oPC, nToken, "chbx_plot_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_plot_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "chbx_plot_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_plot_tooltip", JsonString (" Plot items cannot be sold or destroyed.")); + nValue = GetStolenFlag(oItem); + NuiSetBind(oPC, nToken, "chbx_stolen_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_stolen_check", JsonBool(nValue)); + NuiSetBindWatch (oPC, nToken, "chbx_stolen_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_stolen_tooltip", JsonString (" Stolen items cannot be sold to some stores.")); + nValue = GetItemCursedFlag(oItem); + NuiSetBind(oPC, nToken, "chbx_cursed_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_cursed_check", JsonBool(nValue)); + NuiSetBindWatch (oPC, nToken, "chbx_cursed_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_cursed_tooltip", JsonString (" Cursed items cannot be dropped or sold.")); + nValue = GetIdentified (oItem); + NuiSetBind(oPC, nToken, "chbx_identified_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_identified_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "chbx_identified_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_identified_tooltip", JsonString (" Close inventory and open again to refresh identified state.")); + nValue = GetDroppableFlag(oItem); + NuiSetBind(oPC, nToken, "chbx_droppable_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "chbx_droppable_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "chbx_droppable_check", TRUE); + NuiSetBind(oPC, nToken, "chbx_droppable_tooltip", JsonString (" Droppable items only work on death of an NPC.")); + NuiSetBind(oPC, nToken, "btn_save_uti_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_save_uti_tooltip", JsonString (" Saves item to a UTI file. Update will be used in the game.")); + nValue = GetItemStackSize (oItem); + NuiSetBind(oPC, nToken, "txt_stack_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "txt_stack", JsonString(IntToString (nValue))); + NuiSetBindWatch (oPC, nToken, "txt_stack", TRUE); + nValue = GetItemCharges (oItem); + NuiSetBind(oPC, nToken, "txt_charges_event", JsonBool(TRUE)); + NuiSetBind (oPC, nToken, "txt_charges", JsonString(IntToString (nValue))); + NuiSetBindWatch (oPC, nToken, "txt_charges", TRUE); + NuiSetBind(oPC, nToken, "btn_destroy_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_destroy_tooltip", JsonString(" Destroys the item permanently! Must click twice to destroy the item.")); + // Description + NuiSetBind(oPC, nToken, "txt_desc_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "txt_desc", TRUE); + NuiSetBind(oPC, nToken, "txt_desc_tooltip", JsonString (" Color codes can be used!")); + NuiSetBind(oPC, nToken, "txt_desc", JsonString(GetDescription(oItem))); + // Base Item Description + NuiSetBind(oPC, nToken, "txt_base_desc_event", JsonBool(TRUE)); + //NuiSetBind(oPC, nToken, "txt_desc_tooltip", JsonString ("Color codes can be used!")); + if(sBaseItemDesc != "") NuiSetBind(oPC, nToken, "txt_base_desc", JsonString(sBaseItemDesc)); +} +void CraftItemInfoEvents(object oPC, int nToken) +{ + string sEvent = NuiGetEventType(); + // We don't use and it causes error windows to go off! Return early! + if(sEvent == "mouseup") return; + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + //SendMessageToPC(oPC, "0e_crafting, 1961, sElem: " + sElem + " sEvent: " + sEvent); + object oTarget = GetLocalObject(oPC, CRAFT_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oPC; + // Get the item we are crafting. + int nItemSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetLocalObject(oPC, "CRAFT_INFO_ITEM"); + if(sEvent == "click") + { + if(sElem == "btn_destroy") + { + if(!JsonGetInt(NuiGetBind(oPC, nToken, "btn_destroy"))) + { + if(!GetPlotFlag(oItem)) + { + DestroyObject(oItem); + ai_SendMessages(GetName(oItem) + " has been permanently destroyed!", AI_COLOR_RED, oPC); + NuiDestroy(oPC, nToken); + } + else + { + ai_SendMessages("The plot flag must be removed before you can destroy " + GetName(oItem) + "!", AI_COLOR_YELLOW, oPC); + } + } + else + { + ai_SendMessages("Click Destroy button again to destroy " + GetName(oItem) + "!", AI_COLOR_RED, oPC); + } + } + // Allows saving the item as a UTI! + else if(sElem == "btn_save_uti") + { + json jItem = ObjectToJson(oItem); + string sResRef = JsonGetString(NuiGetBind(oPC, nToken, "txt_item_resref")); + sResRef = ai_RemoveIllegalCharacters(sResRef); + if(sResRef == "") ai_SendMessages(GetName(oItem) + " has not been saved! ResRef does not have a value.", AI_COLOR_RED, oPC); + else + { + JsonToTemplate(jItem, sResRef, RESTYPE_UTI); + ai_SendMessages(GetName(oItem) + " has been saved as " + sResRef + ".uti in your Neverwinter Nights Temp directory.", AI_COLOR_GREEN, oPC); + ai_SendMessages("This temp directory will be removed when the game is left.", AI_COLOR_GREEN, oPC); + } + } + } + if(sEvent == "watch") + { + // Changing the name needs to be before the cooldown. + if(sElem == "txt_item_name") + { + string sName = JsonGetString(NuiGetBind(oPC, nToken, "txt_item_name")); + SetName(oItem, sName); + int nToken2 = NuiFindWindow(oPC, "crafting_nui"); + if(nToken2) NuiSetBind(oPC, nToken2, "txt_item_name", JsonString(sName)); + } + else if(sElem == "txt_item_tag") + { + string sTag = JsonGetString(NuiGetBind(oPC, nToken, "txt_item_tag")); + SetTag(oItem, sTag); + } + else if(sElem == "txt_stack") + { + int nSize = StringToInt(JsonGetString(NuiGetBind(oPC, nToken, "txt_stack"))); + int nBaseItemType = GetBaseItemType(oItem); + string sMaxSize = Get2DAString("baseitems", "Stacking", nBaseItemType); + if(nSize > StringToInt(sMaxSize)) + { + ai_SendMessages("The maximum stack for this item type is " + sMaxSize + ".", AI_COLOR_RED, oPC); + NuiSetBind(oPC, nToken, "txt_stack", JsonString(sMaxSize)); + } + if(nSize != 0) SetItemStackSize(oItem, nSize); + } + else if(sElem == "txt_charges") + { + int nCharges = StringToInt(JsonGetString(NuiGetBind(oPC, nToken, "txt_charges"))); + if(nCharges > 250) + { + ai_SendMessages("The maximum charges for this item type is 250.", AI_COLOR_RED, oPC); + NuiSetBind(oPC, nToken, "txt_charges", JsonString("250")); + } + if(nCharges != 0) SetItemCharges(oItem, nCharges); + } + else if(sElem == "chbx_plot_check") + { + int nValue = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetPlotFlag(oItem, nValue); + } + else if(sElem == "chbx_stolen_check") + { + int nValue = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetStolenFlag(oItem, nValue); + } + else if(sElem == "chbx_cursed_check") + { + int nValue = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetItemCursedFlag(oItem, nValue); + } + else if(sElem == "chbx_identified_check") + { + int nValue = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetIdentified(oItem, nValue); + } + else if(sElem == "chbx_droppable_check") + { + int nValue = JsonGetInt(NuiGetBind(oPC, nToken, sElem)); + SetDroppableFlag(oItem, nValue); + } + } +} +/*void CreateDresserGUIPanel(object oPC, object oTarget) +{ +} + diff --git a/src/module/nss/pe_debug.nss b/src/module/nss/pe_debug.nss new file mode 100644 index 0000000..5b6ad1a --- /dev/null +++ b/src/module/nss/pe_debug.nss @@ -0,0 +1,900 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: pe_debug + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + PEPS Plugin to allow use of special Debug scripts +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +#include "0i_module" +#include "0i_menus" +//#include "prc_inc_eventhk" +// Gets a variable from oTarget, if oTarget is OBJECT_INVALID then +// it will get the variable from the Module and Area. +void debug_GetObjectVariable(object oPC, object oTarget, string sDesc = ""); +// Lists the variables from oTarget to the screen. +void debug_ListObjectVariables(object oPC, object oTarget); +// Force event script change to default for oCreature. +void ai_ForceAssociateEventScriptsToDefault(object oPC, object oCreature); +// Reverts event script change from default for oCreature. +void ai_RevertAssociateEventScriptsToDefault(object oPC, object oCreature); +void main() +{ + // Get the last player to use targeting mode + object oPC = GetLastPlayerToSelectTarget(); + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + if(oPC == OBJECT_SELF && sTargetMode != "") + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + vector vTarget = GetTargetingModeSelectedPosition(); + location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + object oObject = GetLocalObject(oPC, "AI_TARGET_OBJECT"); + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget) && vTarget == Vector()) + { + return; + } + // Targeting code here. + if(sTargetMode == "DEBUG_CREATURE") + { + object oModule = GetModule(); + string sDebugName = GetName(oTarget); + SetLocalString(oModule, AI_RULE_DEBUG_CREATURE, sDebugName); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_DEBUG_CREATURE, JsonString(sDebugName)); + ai_SetCampaignDbJson("rules", jRules); + SetLocalObject(oPC, "AI_RULE_DEBUG_CREATURE_OBJECT", oTarget); + ExecuteScript("pi_debug", oPC); + } + else if(sTargetMode == "CLEAR_REPUTATION") + { + int nReputation = GetFactionAverageReputation(oTarget, oPC); + object oPCMember = GetFirstFactionMember(oPC, FALSE); + while(GetIsObjectValid(oPCMember)) + { + ClearPersonalReputation(oPCMember, oTarget); + oPCMember = GetNextFactionMember(oPC, FALSE); + } + ai_SendMessages("Your reputation with " + GetName(oTarget) + " has been set to neutral.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "SET_REPUTATION") + { + SetStandardFactionReputation(STANDARD_FACTION_COMMONER, 50, oTarget); + SetStandardFactionReputation(STANDARD_FACTION_DEFENDER, 50, oTarget); + SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 50, oTarget); + SetStandardFactionReputation(STANDARD_FACTION_MERCHANT, 50, oTarget); + ai_SendMessages(GetName(oTarget) + " has been set to a neutral reputation.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DEBUG_INFO") + { + ai_SendMessages("Information for " + GetName(oTarget), AI_COLOR_WHITE, oPC); + ai_SendMessages("ResRef: " + GetResRef(oTarget), AI_COLOR_GREEN, oPC); + ai_SendMessages("Tag: " + GetTag(oTarget), AI_COLOR_ORANGE, oPC); + ai_SendMessages("UUID: " + GetObjectUUID(oTarget), AI_COLOR_LIGHT_MAGENTA, oPC); + ai_SendMessages("Faction Commoner: " + IntToString(GetStandardFactionReputation(STANDARD_FACTION_COMMONER, oTarget)), AI_COLOR_GREEN, oPC); + ai_SendMessages("Faction Defender: " + IntToString(GetStandardFactionReputation(STANDARD_FACTION_DEFENDER, oTarget)), AI_COLOR_GREEN, oPC); + ai_SendMessages("Faction Merchant: " + IntToString(GetStandardFactionReputation(STANDARD_FACTION_MERCHANT, oTarget)), AI_COLOR_GREEN, oPC); + ai_SendMessages("Faction Hostile: " + IntToString(GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, oTarget)), AI_COLOR_RED, oPC); + int nObjectType = GetObjectType(oTarget); + if(nObjectType == OBJECT_TYPE_CREATURE) + { + json jObject = ObjectToJson(oTarget); + string sConversation = JsonGetString(GffGetResRef(jObject, "Conversation")); + ai_SendMessages("Conversation: " + sConversation, AI_COLOR_CYAN, oPC); + SendMessageToPC(oPC, "Creature Event Scripts:"); + string sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_NOTICE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_NOTICE SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_END_COMBATROUND SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DIALOGUE SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_MELEE_ATTACKED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DAMAGED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DEATH); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DEATH SCRIPT: " + sScript); + sScript = GetLocalString(oTarget, "AI_ON_DEATH"); + if(sScript != "") + { + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DEATH SECOND SCRIPT: " + sScript); + } + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DISTURBED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_SPAWN_IN SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_RESTED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_RESTED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_SPELLCASTAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_BLOCKED_BY_DOOR SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USER_DEFINED_EVENT SCRIPT: " + sScript); + } + else if(nObjectType == OBJECT_TYPE_DOOR) + { + SendMessageToPC(oPC, "Door Event Scripts:"); + string sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_CLICKED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLICKED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_CLOSE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLOSED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_DAMAGE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DAMAGE SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_DEATH); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DEATH SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_DIALOGUE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DIALOGUE SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_DISARM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DISARM SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_FAIL_TO_OPEN); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_FAIL_TO_OPEN SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_LOCK); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_LOCK SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_MELEE_ATTACKED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_MELEE_ATTACKED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_OPEN); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_OPEN SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_SPELLCASTAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_SPELLCASTAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_TRAPTRIGGERED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_TRAPTRIGGERED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_UNLOCK); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_UNLOCK SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_DOOR_ON_USERDEFINED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USERDEFINED SCRIPT: " + sScript); + } + else if(nObjectType == OBJECT_TYPE_PLACEABLE) + { + SendMessageToPC(oPC, "Placeable Event Scripts:"); + string sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_CLOSED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLOSED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_DAMAGED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DAMAGED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_DEATH); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DEATH SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_DIALOGUE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DIALOGUE SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_DISARM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DISARM SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_INVENTORYDISTURBED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_INVENTORYDISTURBED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_LEFT_CLICK); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_LEFT_CLICK SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_LOCK); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_LOCK SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_MELEEATTACKED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_MELEEATTACKED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_OPEN); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_OPEN SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_SPELLCASTAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_SPELLCASTAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_TRAPTRIGGERED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_TRAPTRIGGERED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_UNLOCK); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_UNLOCK SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_USED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USER_DEFINED_EVENT SCRIPT: " + sScript); + } + else if(nObjectType == OBJECT_TYPE_TRIGGER) + { + SendMessageToPC(oPC, "Trigger Event Scripts:"); + string sScript = GetEventScript(oTarget, EVENT_SCRIPT_TRIGGER_ON_CLICKED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLICKED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_DISARM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_DISARM SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_TRIGGER_ON_OBJECT_ENTER); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_OBJECT_ENTER SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_TRIGGER_ON_OBJECT_EXIT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_OBJECT_EXIT SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_PLACEABLE_ON_TRAPTRIGGERED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_TRAPTRIGGERED SCRIPT: " + sScript); + sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USER_DEFINED_EVENT SCRIPT: " + sScript); + } + else + { + // Area event scripts. + object oArea = GetArea(oPC); + SendMessageToPC(oPC, "Area Event Scripts:"); + string sScript = GetEventScript(oArea, EVENT_SCRIPT_AREA_ON_ENTER); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_ENTER SCRIPT: " + sScript); + sScript = GetEventScript(oArea, EVENT_SCRIPT_AREA_ON_EXIT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_EXIT SCRIPT: " + sScript); + sScript = GetEventScript(oArea, EVENT_SCRIPT_PLACEABLE_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oArea, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USER_DEFINED_EVENT SCRIPT: " + sScript); + // Module event scripts. + object oModule = GetModule(); + SendMessageToPC(oPC, GetModuleName() + " Module Event Scripts."); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_ACQUIRE_ITEM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_ACQUIRE_ITEM SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_ACTIVATE_ITEM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_ACTIVATE_ITEM SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_CLIENT_ENTER); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLIENT_ENTER SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_CLIENT_EXIT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_CLIENT_EXIT SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_EQUIP_ITEM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_EQUIP_ITEM SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_HEARTBEAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_HEARTBEAT SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_LOSE_ITEM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_LOSE_ITEM SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_MODULE_LOAD); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_MODULE_LOAD SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_MODULE_START); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_MODULE_START SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_NUI_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_NUI_EVENT SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_CANCEL_CUTSCENE); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_CANCEL_CUTSCENE SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_CHAT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_CHAT SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_DEATH); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_DEATH SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_DYING); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_DYING SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_GUIEVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_GUIEVENT SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_LEVEL_UP); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_LEVEL_UP SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_REST); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_REST SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_TARGET SCRIPT: " + sScript); + sScript = GetLocalString(oModule, AI_MODULE_TARGET_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + if(sScript != "") + { + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_TARGET SECOND SCRIPT: " + sScript); + } + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TILE_ACTION); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_PLAYER_TILE_ACTION SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_RESPAWN_BUTTON_PRESSED); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_RESPAWN_BUTTON_PRESSED SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_UNEQUIP_ITEM); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_UNEQUIP_ITEM SCRIPT: " + sScript); + sScript = GetEventScript(oModule, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT); + sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]"; + SendMessageToPC(oPC, "ON_USER_DEFINED_EVENT SCRIPT: " + sScript); + } + /* Checks PRC virtual events. See prc_inc_eventhk + int nIndex = 1; + string sEvent = GetFirstEventScript(oTarget, EVENT_VIRTUAL_ONHEARTBEAT, FALSE); + if(sEvent != "") + { + SendMessageToPC(oPC, "HB event script " + IntToString(nIndex) + ": " + sEvent); + for(nIndex = 2; nIndex < 20; nIndex++) + { + sEvent = GetNextEventScript(oTarget, EVENT_VIRTUAL_ONHEARTBEAT, FALSE); + if(sEvent == "") break; + SendMessageToPC(oPC, "HB event script " + IntToString(nIndex) + ": " + sEvent); + } + }*/ + } + else if(sTargetMode == "SET_NPC_SCRIPTS") + { + if(GetLocalString(oTarget, "AI_ON_HEARTBEAT") == "") + { + ai_ForceAssociateEventScriptsToDefault(oPC, oTarget); + } + else ai_RevertAssociateEventScriptsToDefault(oPC, oTarget); + } + else if(sTargetMode == "CLEAR_CREATURE_EVENTS") + { + ai_SendMessages("Set event scripts for " + GetName(oTarget) + " to default.", AI_COLOR_YELLOW, oPC); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_NOTICE, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DEATH, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_RESTED, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "default"); + SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "default"); + DeleteLocalInt(oTarget, "AI_I_AM_BEING_HEALED"); + DeleteLocalString(oTarget, "AIScript"); + ai_ClearCreatureActions(); + } + else if(sTargetMode == "DEBUG_JSON_DUMP") + { + json jObject = ObjectToJson(oTarget, TRUE); + WriteTimestampedLogEntry(GetName(oTarget) + " JsonDump: " + JsonDump(jObject, 1)); + ai_SendMessages(GetName(oTarget) + " has been dumped to the log file!", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DEBUG_LIST_VAR") + { + debug_ListObjectVariables(oPC, oTarget); + } + else if(sTargetMode == "DEBUG_SET_VARIABLE") + { + string sVarName = GetLocalString(oPC, "Debug_Var_Name"); + int nVarType = GetLocalInt(oPC, "Debug_Var_Type"); + if(nVarType == 0) // Int + { + string sVarValue = GetLocalString(oPC, "Debug_Var_Value"); + int nVarValue = StringToInt(sVarValue); + SetLocalInt(oTarget, sVarName, nVarValue); + ai_SendMessages(sVarName + " [Int] has been set to " + IntToString(nVarValue) + " for " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 1) // Float + { + string sVarValue = GetLocalString(oPC, "Debug_Var_Value"); + DeleteLocalString(oPC, "Debug_Var_Name"); + float fVarValue = StringToFloat(sVarValue); + SetLocalFloat(oTarget, sVarName, fVarValue); + ai_SendMessages(sVarName + " [Float] has been set to " + FloatToString(fVarValue, 0, 2) + " for " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 2) // String + { + string sVarValue = GetLocalString(oPC, "Debug_Var_Value"); + SetLocalString(oTarget, sVarName, sVarValue); + ai_SendMessages(sVarName + " [String] has been set to " + sVarValue + " for " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 3) // Object + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalObject(oPC, "AI_TARGET_OBJECT", oTarget); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_OBJECT_VARIABLE"); + ai_SendMessages("Select an object to save to " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | + OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_TRIGGER, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(nVarType == 4) // Location + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalObject(oPC, "AI_TARGET_OBJECT", oTarget); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_LOCATION_VARIABLE"); + ai_SendMessages("Select a location to save to " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_TILE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + DeleteLocalString(oPC, "Debug_Var_Name"); + DeleteLocalInt(oPC, "Debug_Var_Type"); + DeleteLocalString(oPC, "Debug_Var_Value"); + } + else if(sTargetMode == "DEBUG_SET_OBJECT_VARIABLE") + { + string sVarName = GetLocalString(oPC, "Debug_Var_Name"); + SetLocalObject(oObject, sVarName, oTarget); + DeleteLocalObject(oPC, "AI_TARGET_OBJECT"); + DeleteLocalString(oPC, "Debug_Var_Name"); + ai_SendMessages(sVarName + " [Object] has been set to " + GetName(oObject) + " for " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DEBUG_SET_LOCATION_VARIABLE") + { + string sVarName = GetLocalString(oPC, "Debug_Var_Name"); + SetLocalLocation(oObject, sVarName, lLocation); + DeleteLocalObject(oPC, "AI_TARGET_OBJECT"); + DeleteLocalString(oPC, "Debug_Var_Name"); + ai_SendMessages(sVarName + " [Location] has been set to " + LocationToString(lLocation) + " for " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "DEBUG_DELETE_VARIABLE") + { + string sVarName = GetLocalString(oPC, "Debug_Var_Name"); + int nVarType = GetLocalInt(oPC, "Debug_Var_Type"); + if(nVarType == 0) DeleteLocalInt(oTarget, sVarName); + else if(nVarType == 1) DeleteLocalFloat(oTarget, sVarName); + else if(nVarType == 2) DeleteLocalString(oTarget, sVarName); + else if(nVarType == 4) DeleteLocalObject(oTarget, sVarName); + else if(nVarType == 5) DeleteLocalLocation(oTarget, sVarName); + ai_SendMessages(sVarName + " has been deleted from " + GetName(oTarget), AI_COLOR_YELLOW, oPC); + DeleteLocalString(oPC, "Debug_Var_Name"); + DeleteLocalInt(oPC, "Debug_Var_Type"); + } + else if(sTargetMode == "DEBUG_GET_VARIABLE") + { + debug_GetObjectVariable(oPC, oTarget); + } + } + // Run all non-targeting code here, usually NUI events. + else + { + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + //string sWndId = NuiGetWindowId(oPC, nToken); + //********************************************************************** + //if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + if(sEvent == "click") + { + if(sElem == "btn_npc_scripts") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "SET_NPC_SCRIPTS"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select an npc to change scripts for.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE); + } + else if(sElem == "btn_set_reputation") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "SET_REPUTATION"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select a creature to set all standard reputations to neutral.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_clear_reputation") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "CLEAR_REPUTATION"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select a creature to clear your PC's reputation with that creature's faction.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_info") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_INFO"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select an object to send it's information to the players screen.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL , MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_obj_json") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_JSON_DUMP"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select an object to dump it's json values to the log.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | + OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_TRIGGER, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_obj_var") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_LIST_VAR"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select an object to list it's variables to the player screen.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_debug_creature") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_CREATURE"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select a creature to start sending debug information to the log for.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_clear_events") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "CLEAR_CREATURE_EVENTS"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select a creature to set event scripts to default.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_clear_debug") + { + object oModule = GetModule(); + SetLocalString(oModule, AI_RULE_DEBUG_CREATURE, ""); + json jRules = ai_GetCampaignDbJson("rules"); + jRules = JsonObjectSet(jRules, AI_RULE_DEBUG_CREATURE, JsonString("")); + ai_SetCampaignDbJson("rules", jRules); + DeleteLocalObject(oPC, "AI_RULE_DEBUG_CREATURE_OBJECT"); + ai_SendMessages("Creature Debug mode has been cleared.", AI_COLOR_YELLOW, oPC); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_debug", oPC); + } + else if(sElem == "btn_delete_var") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + string sVarName = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")); + SetLocalString(oPC, "Debug_Var_Name", sVarName); + SetLocalString(oPC, "Debug_Var_Value", JsonGetString(NuiGetBind(oPC, nToken, "txt_var_value"))); + SetLocalInt(oPC, "Debug_Var_Type", JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected"))); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_DELETE_VARIABLE"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select Object to delete (" + sVarName + ") variable from.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_get_var") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + string sVarName = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")); + SetLocalString(oPC, "Debug_Var_Name", sVarName); + SetLocalString(oPC, "Debug_Var_Value", JsonGetString(NuiGetBind(oPC, nToken, "txt_var_value"))); + SetLocalInt(oPC, "Debug_Var_Type", JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected"))); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_GET_VARIABLE"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select Object to get (" + sVarName + ") variable from.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_set_var") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + string sVarName = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")); + SetLocalString(oPC, "Debug_Var_Name", sVarName); + SetLocalString(oPC, "Debug_Var_Value", JsonGetString(NuiGetBind(oPC, nToken, "txt_var_value"))); + SetLocalInt(oPC, "Debug_Var_Type", JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected"))); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_VARIABLE"); + NuiDestroy(oPC, nToken); + ai_SendMessages("Select Object to set (" + sVarName + ") variable to.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + } + if(sEvent == "watch") + { + if(sElem == "txt_var_name" || sElem == "txt_var_value" || + sElem == "cmb_var_type_selected") + { + if(JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")) != "") + { + NuiSetBind(oPC, nToken, "btn_get_var_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_delete_var_event", JsonBool(TRUE)); + if(JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected")) == 3 || // Objects + JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected")) == 4 || // Locations + JsonGetString(NuiGetBind(oPC, nToken, "txt_var_value")) != "") + { + NuiSetBind(oPC, nToken, "btn_set_var_event", JsonBool(TRUE)); + return; + } + } + else + { + NuiSetBind(oPC, nToken, "btn_get_var_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_delete_var_event", JsonBool(FALSE)); + } + NuiSetBind(oPC, nToken, "btn_set_var_event", JsonBool(FALSE)); + } + } + if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + if(sElem == "btn_delete_var") + { + object oModule = GetModule(); + // Set Targeting variables. + string sVarName = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")); + int nVarType = JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected")); + if(nVarType == 0) DeleteLocalInt(oModule, sVarName); + else if(nVarType == 1) DeleteLocalFloat(oModule, sVarName); + else if(nVarType == 2) DeleteLocalString(oModule, sVarName); + else if(nVarType == 4) DeleteLocalObject(oModule, sVarName); + else if(nVarType == 5) DeleteLocalLocation(oModule, sVarName); + ai_SendMessages(sVarName + " has been deleted from the Module", AI_COLOR_YELLOW, oPC); + } + else if(sElem == "btn_get_var") + { + // Set Targeting variables. + SetLocalString(oPC, "Debug_Var_Name", JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name"))); + SetLocalInt(oPC, "Debug_Var_Type", JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected"))); + debug_GetObjectVariable(oPC, GetModule(), "(Module)"); + } + else if(sElem == "btn_set_var") + { + // Set Targeting variables. + string sVarName = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_name")); + string sVarValue = JsonGetString(NuiGetBind(oPC, nToken, "txt_var_value")); + int nVarType = JsonGetInt(NuiGetBind (oPC, nToken, "cmb_var_type_selected")); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_VARIABLE"); + if(nVarType == 0) // Int + { + int nVarValue = StringToInt(sVarValue); + SetLocalInt(GetModule(), sVarName, nVarValue); + ai_SendMessages(sVarName + " [Int] has been set to " + IntToString(nVarValue) + " on the Module.", AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 1) // Float + { + float fVarValue = StringToFloat(sVarValue); + SetLocalFloat(GetModule(), sVarName, fVarValue); + ai_SendMessages(sVarName + " [Float] has been set to " + FloatToString(fVarValue, 0, 2) + " on the Module.", AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 2) // String + { + SetLocalString(GetModule(), sVarName, sVarValue); + ai_SendMessages(sVarName + " [String] has been set to " + sVarValue + " on the Module.", AI_COLOR_YELLOW, oPC); + } + else if(nVarType == 3) // Object + { + object oModule = GetModule(); + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, "Debug_Var_Name", sVarName); + SetLocalObject(oPC, "AI_TARGET_OBJECT", oModule); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_OBJECT_VARIABLE"); + ai_SendMessages("Select an object to save to " + GetName(oModule), AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | + OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_TRIGGER, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(nVarType == 4) // Location + { + object oModule = GetModule(); + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug"); + // Set Targeting variables. + SetLocalString(oPC, "Debug_Var_Name", sVarName); + SetLocalObject(oPC, "AI_TARGET_OBJECT", oModule); + SetLocalString(oPC, AI_TARGET_MODE, "DEBUG_SET_LOCATION_VARIABLE"); + ai_SendMessages("Select a location to save to " + GetName(oModule), AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_TILE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + } + } + } + } +} +void debug_GetObjectVariable(object oPC, object oTarget, string sDesc = "") +{ + string sVar, sVarName = GetLocalString(oPC, "Debug_Var_Name"); + int nVarType = GetLocalInt(oPC, "Debug_Var_Type"); + if(nVarType == 0) sVar = IntToString(GetLocalInt(oTarget, sVarName)); + else if(nVarType == 1) sVar = FloatToString(GetLocalFloat(oTarget, sVarName), 0, 2); + else if(nVarType == 2) sVar = GetLocalString(oTarget, sVarName); + else if(nVarType == 4) sVar = GetName(GetLocalObject(oTarget, sVarName)); + else if(nVarType == 5) sVar = LocationToString(GetLocalLocation(oTarget, sVarName)); + ai_SendMessages(sVarName + " on " + GetName(oTarget) + sDesc + " is set to " + sVar, AI_COLOR_YELLOW, oPC); +} +void debug_ListObjectVariables(object oPC, object oTarget) +{ + string sName = GetName(oTarget); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + ai_SendMessages(sName + " variables:", AI_COLOR_GREEN, oPC); + json jObject = ObjectToJson(oTarget, TRUE); + json jVarTable = GffGetList(jObject, "VarTable"); + string sVariable; + int nIndex, nVarType; + json jVar = JsonArrayGet(jVarTable, nIndex); + while(JsonGetType(jVar) != JSON_TYPE_NULL) + { + sVariable = JsonGetString(GffGetString(jVar, "Name")); + nVarType = JsonGetInt(GffGetDword(jVar, "Type")); + if(nVarType == 1) + { + sVariable += " [int] "; + sVariable += IntToString(JsonGetInt(GffGetInt(jVar, "Value"))); + } + else if(nVarType == 2) + { + sVariable += " [float] "; + sVariable += FloatToString(JsonGetFloat(GffGetFloat(jVar, "Value")), 0, 2); + } + else if(nVarType == 3) + { + sVariable += " [string] "; + sVariable += JsonGetString(GffGetString(jVar, "Value")); + } + else if(nVarType == 4) + { + sName = GetName(GetLocalObject(oTarget, sVariable)); + sVariable += " [object] " + sName; + } + else if(nVarType == 5) + { + sName = LocationToString(GetLocalLocation(oTarget, sVariable)); + sVariable += " [location] " + sName; + } + else if(nVarType == 7) + { + sVariable += " [struct] "; + sVariable += JsonDump(GffGetStruct(jVar, "Value")); + } + sVariable += JsonGetString(JsonObjectGet(jVar, "Value")); + ai_SendMessages(sVariable, AI_COLOR_YELLOW, oPC); + jVar = JsonArrayGet(jVarTable, ++nIndex); + } + if(!nIndex) ai_SendMessages("No variables to list!", AI_COLOR_YELLOW, oPC); +} +void ai_ForceAssociateEventScriptsToDefault(object oPC, object oCreature) +{ + ai_SendMessages("Changing " + GetName(oCreature) + "'s event scripts to default event scripts!", AI_COLOR_YELLOW, oPC); + ai_SendMessages("Use this tool on them again to revert this creatures event scripts back!", AI_COLOR_YELLOW, oPC); + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + if(sScript == "0e_id_events" || sScript == "0e_prc_id_events") + { + ai_SendMessages("You cannot use this on creatures in Infinite Dungeons!"); + return; + } + SetLocalString(oCreature, "AI_ON_HEARTBEAT", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_ch_ac1"); + //********** On Perception ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE); + SetLocalString(oCreature, "AI_ON_NOTICE", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_ch_ac2"); + //********** On End Combat Round ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND); + SetLocalString(oCreature, "AI_ON_END_COMBATROUND", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_ch_ac3"); + //********** On Dialogue ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE); + SetLocalString(oCreature, "AI_ON_DIALOGUE", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "nw_ch_ac4"); + //********** On Melee Attacked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED); + SetLocalString(oCreature, "AI_ON_MELEE_ATTACKED", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "nw_ch_ac5"); + //********** On Damaged ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED); + SetLocalString(oCreature, "AI_ON_DAMAGED", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "nw_ch_ac6"); + //********** On Disturbed ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED); + SetLocalString(oCreature, "AI_ON_DISTURBED", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "nw_ch_ac8"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //********** On Rested ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED); + SetLocalString(oCreature, "AI_ON_RESTED", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, "nw_ch_aca"); + //********** On Spell Cast At ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT); + SetLocalString(oCreature, "AI_ON_SPELLCASTAT", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "nw_ch_acb"); + //********** On Blocked ********** + sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR); + SetLocalString(oCreature, "AI_ON_BLOCKED_BY_DOOR", sScript); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "nw_ch_acb"); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); + if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature); +} +void ai_RevertAssociateEventScriptsToDefault(object oPC, object oCreature) +{ + ai_SendMessages("Changing " + GetName(oCreature) + "'s event scripts back to original!", AI_COLOR_YELLOW, oPC); + //********** On Heartbeat ********** + string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + if(sScript == "0e_id_events" || sScript == "0e_prc_id_events") + { + ai_SendMessages("You cannot use this on creatures in Infinite Dungeons!", AI_COLOR_RED, oPC); + return; + } + sScript = GetLocalString(oCreature, "AI_ON_HEARTBEAT"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, sScript); + //********** On Perception ********** + sScript = GetLocalString(oCreature, "AI_ON_NOTICE"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, sScript); + //********** On End Combat Round ********** + sScript = GetLocalString(oCreature, "AI_ON_END_COMBATROUND"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, sScript); + //********** On Dialogue ********** + sScript = GetLocalString(oCreature, "AI_ON_DIALOGUE"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, sScript); + //********** On Melee Attacked ********** + sScript = GetLocalString(oCreature, "AI_ON_MELEE_ATTACKED"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, sScript); + //********** On Damaged ********** + sScript = GetLocalString(oCreature, "AI_ON_DAMAGED"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, sScript); + //********** On Disturbed ********** + sScript = GetLocalString(oCreature, "AI_ON_DISTURBED"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, sScript); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, ""); + //********** On Rested ********** + sScript = GetLocalString(oCreature, "AI_ON_RESTED"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_RESTED, sScript); + //********** On Spell Cast At ********** + sScript = GetLocalString(oCreature, "AI_ON_SPELLCASTAT"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript); + //********** On Blocked ********** + sScript = GetLocalString(oCreature, "AI_ON_BLOCKED_BY_DOOR"); + SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, sScript); + //SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, ""); + if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature); +} + diff --git a/src/module/nss/pe_henchmen.nss b/src/module/nss/pe_henchmen.nss new file mode 100644 index 0000000..4f6bf42 --- /dev/null +++ b/src/module/nss/pe_henchmen.nss @@ -0,0 +1,589 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pe_henchmen +//////////////////////////////////////////////////////////////////////////////// + Used with pe_henchmen to run the npc plugin for + Philos Single Player Enhancements. +*/////////////////////////////////////////////////////////////////////////////// +#include "pinc_henchmen" +#include "x0_i0_henchman" +#include "0i_module" +// Creates the Henchman widget. +void PopupWidgetHenchmanGUIPanel(object oPC); +void ResetHenchmanWindows(object oPC, int nToken, object oHenchman) +{ + DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "henchman_nui"))); + DelayCommand(0.1, ExecuteScript("pi_henchmen", oPC)); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.2, CreateCharacterEditGUIPanel(oPC, oHenchman)); +} +void main() +{ + //************************************************************************** + //********************** Henchmen Targeting Execution ********************** + //************************************************************************** + // Get the last player to use targeting mode + object oPC = GetLastPlayerToSelectTarget(); + if(GetLocalInt (oPC, "0_No_Win_Save")) return; + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + if(oPC == OBJECT_SELF && sTargetMode != "") + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + vector vTarget = GetTargetingModeSelectedPosition(); + location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + object oObject = GetLocalObject(oPC, "AI_TARGET_OBJECT"); + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget) && vTarget == Vector()) + { + return; + } + // Targeting code here. + if(sTargetMode == "MAKE_NPC_HENCHMAN") + { + if(GetAssociateType(oTarget) == ASSOCIATE_TYPE_HENCHMAN) + { + ai_SendMessages(GetName(oTarget) + " is already a henchman!", AI_COLOR_RED, oPC); + return; + } + oTarget = CopyObject(oTarget, GetLocation(oPC), OBJECT_INVALID, "", TRUE); + ai_ClearCombatState(oTarget); + ChangeToStandardFaction(oTarget, STANDARD_FACTION_DEFENDER); + DeleteLocalInt(oTarget, AI_ONSPAWN_EVENT); + ai_ChangeEventScriptsForAssociate(oTarget); + AddHenchman(oPC, oTarget); + // Special check for Infinite Dungeon plot givers to be changed into henchman. + if(GetStringLeft(GetLocalString(oTarget, "sConversation"), 8) == "id1_plot") + { + DeleteLocalString(oTarget, "sConversation"); + } + // Remove this variable so they may get a unique tag associate widget. + DeleteLocalString(oTarget, AI_TAG); + ai_SendMessages(GetName(oTarget) + " has been copied and is now in your party as a henchman.", AI_COLOR_GREEN, oPC); + //ExecuteScript("pi_henchmen", oPC); + } + } + //************************************************************************** + //*********************** Henchmen Elements Execution ********************** + //************************************************************************** + else + { + // Let the inspector handle what it wants. + //HandleWindowInspectorEvent (); + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + string sWndId = NuiGetWindowId (oPC, nToken); + //SendMessageToPC(oPC, "pe_henchmen , 26 sWndId: " + sWndId + " sEvent: " + sEvent + " sElem: " + sElem + + // " nToken: " + IntToString(nToken) + " nIndex: " + IntToString(nIndex) + + // " oPC: " + GetName(oPC)); + //********************************************************************** + // Watch to see if the window moves and save. + if(sElem == "window_geometry" && sEvent == "watch") + { + if(GetLocalInt(oPC, "AI_NO_NUI_SAVE")) return; + json jGeometry = NuiGetBind(oPC, nToken, "window_geometry"); + json jData = GetHenchmanDbJson(oPC, "henchman", "0"); + if(JsonGetType(jData) == JSON_TYPE_NULL) jData = JsonObject(); + jData = JsonObjectSet(jData, sWndId, jGeometry); + SetHenchmanDbJson(oPC, "henchman", jData, "0"); + } + else if(sWndId == "henchman_nui") + { + //********************************************************************** + // Henchman menu. + if(sEvent == "click") + { + string sParty = GetHenchmanDbString(oPC, "henchname", "0"); + // Change to a different saved party #. + if(GetStringLeft(sElem, 9) == "btn_party") + { + sParty = GetStringRight(sElem, 1); + SetHenchmanDbString(oPC, "henchname", sParty, "0"); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ExecuteScript("pi_henchmen", oPC)); + } + // Add an NPC in the game as a henchman. + else if(sElem == "btn_npc_henchman") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_henchmen"); + // Set Targeting variables. + SetLocalString(oPC, AI_TARGET_MODE, "MAKE_NPC_HENCHMAN"); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + ai_SendMessages("Select an NPC to copy and make your henchman.", AI_COLOR_YELLOW, oPC); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL , MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE); + } + // ******************* Saved Character buttons ********************* + // Show saved party member. + else if(sElem == "btn_saved_char") + { + string sIndex = IntToString(nIndex); + SetHenchmanDbString(oPC, "henchname", sIndex, sParty); + AddSavedCharacterInfo(oPC, nToken, sParty); + } + // Have any saved henchman not in the party join. + else if(sElem == "btn_join_party") + { + SavedPartyJoin(oPC, nToken, sParty); + } + else if(sElem == "btn_saved_join") + { + SavedCharacterJoin(oPC, nToken, sParty); + } + else if(sElem == "btn_saved_remove") + { + string sIndex = GetHenchmanDbString(oPC, "henchname", sParty); + RemoveHenchmanDb(oPC, sParty + sIndex); + if(GetHenchmanDbString(oPC, "henchname", sParty + "0") == "") + { + SetHenchmanDbString(oPC, "henchname", "", sParty); + } + else SetHenchmanDbString(oPC, "henchname", "0", sParty); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ExecuteScript("pi_henchmen", oPC)); + } + else if(sElem == "btn_clear_party") + { + SavedPartyCleared(oPC, nToken, sParty); + } + // ******************* Current Character buttons ********************* + // Show current party member. + else if(sElem == "btn_cur_char") + { + string sIndex = IntToString(nIndex); + SetHenchmanDbString(oPC, "image", sIndex, sParty); + AddCurrentCharacterInfo(oPC, nToken, sParty); + } + // The edit button, for now we are using it to level up! + else if(sElem == "btn_cur_edit") + { + object oHenchman = GetSelectedHenchman(oPC, sParty); + SetLocalObject(oPC, HENCHMAN_TO_EDIT, oHenchman); + CreateCharacterEditGUIPanel(oPC, oHenchman); + } + else if(sElem == "btn_cur_remove") + { + RemoveYourHenchman(oPC, nToken, sParty); + } + else if(sElem == "btn_remove_party") + { + RemoveWholeParty(oPC, nToken, sParty); + } + else if(sElem == "btn_cur_save") + { + SaveYourHenchman(oPC, nToken, sParty); + SetHenchmanDbString(oPC, "henchname", "0", sParty); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, ExecuteScript("pi_henchmen", oPC)); + } + else if(sElem == "btn_save_party") + { + SaveWholeParty(oPC, nToken, sParty); + } + } + /*else if(sEvent == "watch") + { + if(sElem == "henchman_widget_check") + { + int bWidget = JsonGetInt(NuiGetBind(oPC, nToken, "henchman_widget_check")); + SetLocalInt(oPC, "AI_WIDGET_HENCHMAN", bWidget); + if(bWidget) PopupWidgetHenchmanGUIPanel(oPC); + else DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "widgethenchmanwin"))); + } + if(sElem == "lock_henchman_widget_check") + { + int bBuffLockWidget = JsonGetInt(NuiGetBind(oPC, nToken, "lock_henchman_widget_check")); + SetLocalInt(oPC, "AI_WIDGET_HENCHMAN_LOCK", bBuffLockWidget); + SetLocalInt(oPC, "AI_WIDGET_HENCHMAN", TRUE); + NuiSetBind(oPC, nToken, "henchman_widget_check", JsonBool(TRUE)); + PopupWidgetHenchmanGUIPanel(oPC); + } + } + //************************************************************************** + // Spell Buffing. + else if (sWndId == "widget_henchman") + { + if (sEvent == "click") + { + string sParty; + if (sElem == "btn_one") sParty = "1"; + if (sElem == "btn_two") sParty = "2"; + if (sElem == "btn_three") sParty = "3"; + if (sElem == "btn_four") sParty = "4"; + SetHenchmanDbString (oPC, "henchname", sParty, "0"); + PopupWidgetHenchmanGUIPanel(oPC); + } + } */ + } + else if(sWndId == "henchman_edit_nui") + { + int nChange = 0; + int nID; + string sResRef, sID, sPlot; + object oHenchman = GetLocalObject(oPC, HENCHMAN_TO_EDIT); + if(sEvent == "watch") + { + if(sElem == "char_name") + { + string sName = JsonGetString(NuiGetBind(oPC, nToken, "char_name")); + SetName(oHenchman, sName); + } + if(sElem == "port_name") + { + if(GetLocalInt(oPC, "AI_PORTRAIT_ID_SET")) + { + DeleteLocalInt(oPC, "AI_PORTRAIT_ID_SET"); + //nID = JsonGetInt(NuiGetUserData(oPC, nToken)); + //SetPortraitId(oHenchman, nID); + } + else NuiSetUserData(oPC, nToken, JsonInt(-1)); + sResRef = JsonGetString (NuiGetBind(oPC, nToken, "port_name")); + if(ResManGetAliasFor(sResRef + "l", RESTYPE_TGA) == "" && + ResManGetAliasFor(sResRef + "l", RESTYPE_DDS) == "") + { + if(GetGender(oHenchman)) sResRef = "po_hu_f_99_"; + else sResRef = "po_hu_m_99_"; + } + NuiSetBind (oPC, nToken, "port_resref_image", JsonString (sResRef + "l")); + } + else if(sElem == "cmb_class_selected") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + int nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_class_selected")); + int nClass = GetClassBySelection2DA(nSelection); + SetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nPosition), nClass); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, CreateCharacterEditGUIPanel(oPC, oHenchman)); + } + else if(sElem == "cmb_package_selected") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + string sClass = IntToString(GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nPosition))); + int nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_package_selected")); + int nPackage = GetPackageBySelection2DA(sClass, nSelection); + SetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nPosition), nPackage); + } + else if(sElem == "cmb_soundset_selected") + { + int nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_soundset_selected")); + int nSoundSet = GetSoundSetBySelection2DA(oHenchman, nSelection); + SetSoundset(oHenchman, nSoundSet); + string sResRef = GetStringLowerCase(Get2DAString("soundset", "RESREF", nSoundSet)); + if(GetStringLeft(sResRef, 4) == "vs_f") + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 11, ":1:2:3:22:34:35:41:42:44:45:46:")); + } + else if(GetStringLeft(sResRef, 4) == "vs_n") + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 10, ":1:2:3:34:35:36:40:42:44:45:")); + } + else + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 7, ":1:2:3:11:12:13:33:")); + } + } + } + if(sEvent == "click") + { + if (sElem == "btn_desc_save") + { + string sDescription = JsonGetString(NuiGetBind(oPC, nToken, "desc_value")); + SetDescription(oHenchman, sDescription); + return; + } + else if(sElem == "btn_level_up") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + int nClass = GetClassByPosition(nPosition, oHenchman); + if(nClass == CLASS_TYPE_INVALID) + { + nClass = GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nPosition)); + int nIndex = 1; + while(nIndex < 5) + { + if(nClass == GetClassByPosition(nIndex, oHenchman)) + { + ai_SendMessages(GetName(oHenchman) + " already has this class in a different slot! You can only level up this class in its original slot.", AI_COLOR_RED, oPC); + return; + } + nIndex++; + } + } + int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nPosition)); + if(nPackage == 0) nPackage = GetPackageBySelection2DA(IntToString(nClass), 0); + else if(nPackage == -1) + { + ai_SendMessages("There is not a valid package for this class!", AI_COLOR_RED, oPC); + return; + } + string sLevel = IntToString(GetLevelByClass(nClass, oHenchman) + 1); + json jHenchman = ObjectToJson(oHenchman, TRUE); + //WriteTimestampedLogEntry("pe_henchmen, 318, jHenchman: " + JsonDump(jHenchman, 4)); + // Check to see if this character has a LvlStatList that is required to level. + json jLvlStatList = JsonObjectGet(jHenchman, "LvlStatList"); + //WriteTimestampedLogEntry("pe_henchmen, 321, jLvlStatList: " + JsonDump(jLvlStatList, 4)); + if(JsonGetType(jLvlStatList) == JSON_TYPE_NULL) + { + RemoveHenchman(oPC, oHenchman); + // Make sure to get a clean faction version of the henchman here. + jHenchman = ObjectToJson(oHenchman, TRUE); + jHenchman = CreateLevelStatList(jHenchman, oHenchman, oPC); + location lLocation = GetLocation(oHenchman); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHenchman); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHenchman); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); + DestroyObject(oHenchman); + oHenchman = ai_AddHenchman(oPC, jHenchman, lLocation, nFamiliar, nCompanion); + SetLocalObject(oPC, HENCHMAN_TO_EDIT, oHenchman); + // We need to move party button list index to the last one since + // the henchman will move to the last henchman slot. + int nIndex = 1; + object oHench = GetHenchman(oPC, nIndex); + while(oHench != OBJECT_INVALID) + { + oHench = GetHenchman(oPC, ++nIndex); + //SendMessageToPC(oPC, "oHench: " + GetName(oHench) + " nIndex: " + IntToString(nIndex)); + } + string sParty = GetHenchmanDbString(oPC, "henchname", "0"); + SetHenchmanDbString(oPC, "image", IntToString(nIndex - 1), sParty); + } + int nLeveled = LevelUpHenchman(oHenchman, nClass, TRUE, nPackage); + //SendMessageToPC(oPC, "pe_henchmen, 282, nClass: " + IntToString(nClass) + + // " nPackage: " + IntToString(nPackage) + " nPosition: " + IntToString(nPosition) + + // " nLeveled: " + IntToString(nLeveled)); + string sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + if(!nLeveled) + { + //WriteTimestampedLogEntry("pe_henchmen, 306, jLvlStatList: " + JsonDump(jLvlStatList, 1)); + ai_SendMessages(GetName(oHenchman) + " could not level " + sClass + " to level " + sLevel + "!", AI_COLOR_RED, oPC); + } + else + { + ai_SendMessages(GetName(oHenchman) + " has leveled " + sClass + " to " + sLevel + " level!", AI_COLOR_GREEN, oPC); + ResetHenchmanWindows(oPC, nToken, oHenchman); + } + return; + } + else if(sElem == "btn_reset") + { + oHenchman = ResetCharacter(oPC, oHenchman); + SetLocalObject(oPC, HENCHMAN_TO_EDIT, oHenchman); + ai_SendMessages(GetName(oHenchman) + " has been reset to level 1!", AI_COLOR_GREEN, oPC); + // We need to move party button list index to the last one since + // the henchman will move to the last henchman slot. + int nIndex = 1; + object oHench = GetHenchman(oPC, nIndex); + while(oHench != OBJECT_INVALID) + { + oHench = GetHenchman(oPC, ++nIndex); + } + string sParty = GetHenchmanDbString(oPC, "henchname", "0"); + SetHenchmanDbString(oPC, "image", IntToString(nIndex - 1), sParty); + ResetHenchmanWindows(oPC, nToken, oHenchman); + } + else if(sElem == "btn_portrait_next") + { + nID = JsonGetInt(NuiGetUserData(oPC, nToken)) + 1; + nChange = 1; + } + else if(sElem == "btn_portrait_prev") + { + nID = JsonGetInt(NuiGetUserData(oPC, nToken)) - 1; + nChange = -1; + } + else if(sElem == "btn_portrait_ok") + { + nID = JsonGetInt(NuiGetUserData(oPC, nToken)); + if(nID != -1) SetPortraitId(oHenchman, nID); + else + { + sResRef = JsonGetString (NuiGetBind (oPC, nToken, "port_name")); + if(ResManGetAliasFor(sResRef + "l", RESTYPE_TGA) == "" && + ResManGetAliasFor(sResRef + "l", RESTYPE_DDS) == "") + { + if(GetGender(oHenchman)) sResRef = "po_hu_f_99_"; + else sResRef = "po_hu_m_99_"; + SetPortraitResRef(oHenchman, sResRef); + } + } + int nHenchToken = NuiFindWindow(oPC, "henchman_nui"); + if(nHenchToken) + { + string sImage = GetPortraitResRef(oHenchman); + NuiSetBind(oPC, nHenchToken, "img_cur_portrait_image", JsonString(sImage + "l")); + } + } + if (nChange != 0) + { + int nPRace, nPGender; + int nMax2DARow = Get2DARowCount("portraits") - 1; + if(nID > 5000) nID = 1; + if(nID < 0) nID = 5000; + int nGender = GetGender(oHenchman); + int nRace = GetRacialType(oHenchman); + string sPRace = Get2DAString("portraits", "Race", nID); + if(sPRace != "") nPRace = StringToInt(sPRace); + else nPRace = -1; + string sResRef, sPGender = Get2DAString("portraits", "Sex", nID); + if(sPGender != "") nPGender = StringToInt(sPGender); + else nPGender = -1; + //WriteTimestampedLogEntry("pe_henchmen, 367, nGender: " + IntToString(nGender) + + // " nPGender: " + IntToString(nPGender) + + // " nRace: " + IntToString(nRace) + " nPRace: " + IntToString(nPRace) + + // " nID: " + IntToString(nID)); + while((nRace != nPRace && + (nRace != RACIAL_TYPE_HALFELF || + (nPRace != RACIAL_TYPE_ELF || nPRace != RACIAL_TYPE_HUMAN))) || + nGender != nPGender && nPGender != 4) + { + nID += nChange; + //WriteTimestampedLogEntry("pe_henchmen, 382, nCounter: " + IntToString(nCounter) + + // " nMax2DARow: " + IntToString(nMax2DARow)); + if (nID > 5000) nID = 1; + if (nID < 1) nID = 5000; + sPRace = Get2DAString("portraits", "Race", nID); + if(sPRace != "") nPRace = StringToInt(sPRace); + else nPRace = -1; + sPGender = Get2DAString("portraits", "Sex", nID); + if(sPGender != "") nPGender = StringToInt(sPGender); + else nPGender = -1; + //WriteTimestampedLogEntry("pe_henchmen, 385, nGender: " + IntToString(nGender) + + // " nPGender: " + IntToString(nPGender) + " sPGender: " + sPGender + + // " nRace: " + IntToString(nRace) + " nPRace: " + IntToString(nPRace) + + // " sPRace: " + sPRace + " nID: " + IntToString(nID)); + sResRef = "po_" + Get2DAString("portraits", "BaseResRef", nID) + "l"; + if(ResManGetAliasFor(sResRef, RESTYPE_TGA) == "" && + ResManGetAliasFor(sResRef, RESTYPE_DDS) == "") nPRace = 99; + } + sResRef = "po_" + Get2DAString("portraits", "BaseResRef", nID); + NuiSetUserData(oPC, nToken, JsonInt (nID)); + // This is passed to the portrait name txt that actually sets + // the portrait information and tells it we picked an ID. + SetLocalInt(oPC, "AI_PORTRAIT_ID_SET", TRUE); + NuiSetBind(oPC, nToken, "port_name", JsonString (sResRef)); + } + } + if(sEvent == "mousedown") + { + int nMouseButton = JsonGetInt(JsonObjectGet(NuiGetEventPayload(), "mouse_btn")); + if (sElem == "opt_classes" && nMouseButton == NUI_MOUSE_BUTTON_LEFT) + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")); + SetLocalInt(oHenchman, "CLASS_OPTION_POSITION", nPosition); + DelayCommand(0.0, NuiDestroy(oPC, nToken)); + DelayCommand(0.1, CreateCharacterEditGUIPanel(oPC, oHenchman)); + return; + } + if(nMouseButton == NUI_MOUSE_BUTTON_RIGHT) + { + if(sElem == "cmb_class") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + int nClass = GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nPosition)); + string sName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + string sDescription = GetStringByStrRef(StringToInt(Get2DAString("classes", "Description", nClass))); + string sIcon = Get2DAString("classes", "Icon", nClass); + CreateCharacterDescriptionNUI(oPC, sName, sIcon, sDescription); + } + else if(sElem == "cmb_package") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + int nClass = GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nPosition)); + int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nPosition)); + string sName = GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nPackage))); + string sDescription = GetStringByStrRef(StringToInt(Get2DAString("packages", "Description", nPackage))); + string sIcon = Get2DAString("classes", "Icon", nClass); + CreateCharacterDescriptionNUI(oPC, sName, sIcon, sDescription); + } + else if(sElem == "cmb_soundset") + { + int nSelection = JsonGetInt(NuiGetBind(oPC, nToken, "cmb_soundset_selected")); + int nSoundSet = GetSoundSetBySelection2DA(oHenchman, nSelection); + string sResRef = GetStringLowerCase(Get2DAString("soundset", "RESREF", nSoundSet)); + if(GetStringLeft(sResRef, 4) == "vs_f") + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 11, ":1:2:3:22:34:35:41:42:44:45:46:")); + } + else if(GetStringLeft(sResRef, 4) == "vs_n") + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 10, ":1:2:3:34:35:36:40:42:44:45:")); + } + else + { + DelayCommand(0.1, ai_HaveCreatureSpeak(oHenchman, 7, ":1:2:3:11:12:13:33:")); + } + } + else if(sElem == "opt_classes") + { + int nPosition = JsonGetInt(NuiGetBind(oPC, nToken, "opt_classes_value")) + 1; + int nClass = GetClassByPosition(nPosition, oHenchman); + if(nClass != CLASS_TYPE_INVALID) + { + string sName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + string sDescription = GetStringByStrRef(StringToInt(Get2DAString("classes", "Description", nClass))); + int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nPosition)); + string sPackageName = GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nPackage))); + sDescription += "\n\nPACKAGE: \n" + sPackageName + "\n"; + sDescription += GetStringByStrRef(StringToInt(Get2DAString("packages", "Description", nPackage))); + string sIcon = Get2DAString("classes", "Icon", nClass); + CreateCharacterDescriptionNUI(oPC, sName, sIcon, sDescription); + } + } + } + } + } + else if(sWndId == "char_description_nui") + { + if(sEvent == "click" && sElem == "btn_ok") DelayCommand(0.0, NuiDestroy(oPC, nToken)); + } + } +} +void PopupWidgetHenchmanGUIPanel(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt (oPC, "AI_NO_NUI_SAVE", TRUE); + DelayCommand (0.5f, DeleteLocalInt (oPC, "AI_NO_NUI_SAVE")); + // Row 1 (buttons)********************************************************** + json jRow = CreateButtonImage(JsonArray(), "ir_level1", "btn_one", 30.0f, 30.0f); + jRow = CreateButtonImage(jRow, "ir_level2", "btn_two", 30.0f, 30.0f); + jRow = CreateButtonImage(jRow, "ir_level3", "btn_three", 30.0f, 30.0f); + jRow = CreateButtonImage(jRow, "ir_level4", "btn_four", 30.0f, 30.0f); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + int bAINPCWidgetLock = GetLocalInt(oPC, "AI_WIDGET_HENCHMAN_LOCK"); + // Get the window location to restore it from the database. + float fX = GetLocalFloat(oPC, "widget_henchman_X"); + float fY = GetLocalFloat(oPC, "widget_henchman_Y"); + if(fX == 0.0f && fY == 0.0f) + { + fX = 10.0f; + fY = 10.0f; + } + if(bAINPCWidgetLock) + { + fX = fX + 4.0f; + fY = fY + 45.0f; + } + // Set the layout of the window. + json jLayout = NuiCol (jCol); + int nToken; + if(bAINPCWidgetLock) nToken = SetWindow (oPC, jLayout, "widget_henchman", "Henchman Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_npc"); + else nToken = SetWindow (oPC, jLayout, "widget_henchman", "Henchman Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_npc"); + // Set event watches for window inspector and save window location. + NuiSetBindWatch (oPC, nToken, "collapsed", TRUE); + NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE); + // Set the buttons to show events. + //NuiSetBind (oPC, nToken, "btn_one", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_one_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_two", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_two_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_three", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_three_event", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_four", JsonBool (TRUE)); + NuiSetBind (oPC, nToken, "btn_four_event", JsonBool (TRUE)); +} diff --git a/src/module/nss/pe_mod_set.nss b/src/module/nss/pe_mod_set.nss new file mode 100644 index 0000000..9c251b9 --- /dev/null +++ b/src/module/nss/pe_mod_set.nss @@ -0,0 +1,119 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: pe_mod_settings + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + PEPS Plugin to set module and area settings. +/*////////////////////////////////////////////////////////////////////////////// +const string AI_MODULE_HEARTBEAT_SCRIPT = "AI_MODULE_HEARTBEAT_SCRIPT"; + +#include "0i_main" +void main() +{ + // Get the last player to use targeting mode + object oPC = GetLastPlayerToSelectTarget(); + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + if(oPC == OBJECT_SELF && sTargetMode != "") + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + vector vTarget = GetTargetingModeSelectedPosition(); + location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + object oAssociate = GetLocalObject(oPC, AI_TARGET_ASSOCIATE); + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget) && vTarget == Vector()) + { + return; + } + // Targeting code here. + if(sTargetMode == "TEST_LEVEL_TARGET") + { + int nLevel = ai_GetCharacterLevels(oTarget); + int nXPNeeded = StringToInt(Get2DAString("exptable", "XP", nLevel)); + int nXPToGive = nXPNeeded - GetXP(oTarget); + GiveXPToCreature(oTarget, nXPToGive); + ai_SendMessages(GetName(oTarget) + " has gained " + IntToString(nXPToGive) + " experience to gain 1 level.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "TEST_GOLD_TARGET") + { + GiveGoldToCreature(oTarget, 10000); + ai_SendMessages(GetName(oTarget) + " has gained 10,000 gold.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "TEST_REST_TARGET") + { + ForceRest(oTarget); + ai_SendMessages(GetName(oTarget) + " has rested.", AI_COLOR_GREEN, oPC); + } + else if(sTargetMode == "TEST_HEAL_TARGET") + { + int nHeal = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if(nHeal > 0) + { + effect eHeal = EffectHeal(nHeal); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + ai_SendMessages(GetName(oTarget) + " has been healed.", AI_COLOR_GREEN, oPC); + } + } + else if(sTargetMode == "TEST_ID_TARGET") SetIdentified(oTarget, !GetIdentified(oTarget)); + else if(sTargetMode == "TEST_CLEAR_TARGET") + { + ClearAllActions(TRUE, oTarget); + } + else if(sTargetMode == "TEST_KILL_TARGET") + { + effect eDmg = EffectDamage(10000); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); + ai_SendMessages(GetName(oTarget) + " has been killed.", AI_COLOR_RED, oPC); + } + else if(sTargetMode == "TEST_REMOVE_TARGET") + { + SetIsDestroyable(TRUE, FALSE, FALSE, oTarget); + DestroyObject(oTarget); + ai_SendMessages(GetName(oTarget) + " has been removed!", AI_COLOR_RED, oPC); + } + } + // Run all non-targeting code here, usually NUI events. + else + { + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + //string sWndId = NuiGetWindowId(oPC, nToken); + //********************************************************************** + //if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + if(sEvent == "click") + { + if(sElem == "btn_combat_music_off") + { + object oArea = GetFirstArea(); + while(GetIsObjectValid(oArea)) + { + MusicBattleChange(oArea, 0); + oArea = GetNextArea(); + } + ai_SendMessages(GetModuleName() + " has had the combat music removed. Save your game or you may loose this change!", AI_COLOR_GREEN, oPC); + } + if(sElem == "btn_night_to_day") + { + object oModule = GetModule(); + string sScript = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_HEARTBEAT); + if(sScript == "pc_mod_set") + { + sScript = GetLocalString(oPC, AI_MODULE_HEARTBEAT_SCRIPT); + SetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_HEARTBEAT, sScript); + DeleteLocalString(oPC, AI_MODULE_HEARTBEAT_SCRIPT); + SendMessageToPC(oPC, "Module has been set to use normal time passage!"); + } + else + { + SetLocalString(oPC, AI_MODULE_HEARTBEAT_SCRIPT, sScript); + SetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_HEARTBEAT, "pc_mod_set"); + SendMessageToPC(oPC, "Module has been set to pass through nighttime to make it morning!"); + } + } + } + } +} + + diff --git a/src/module/nss/pe_test.nss b/src/module/nss/pe_test.nss new file mode 100644 index 0000000..7fd799c --- /dev/null +++ b/src/module/nss/pe_test.nss @@ -0,0 +1,227 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script Name: pe_test + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + PEPS Plugin to help test errors. + Gives gold, Heals, etc. +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_main" +void main() +{ + // Get the last player to use targeting mode + object oPC = GetLastPlayerToSelectTarget(); + string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE); + if(oPC == OBJECT_SELF && sTargetMode != "") + { + // Get the targeting mode data + object oTarget = GetTargetingModeSelectedObject(); + vector vTarget = GetTargetingModeSelectedPosition(); + location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC)); + object oAssociate = GetLocalObject(oPC, AI_TARGET_ASSOCIATE); + // If the user manually exited targeting mode without selecting a target, return + if(!GetIsObjectValid(oTarget) && vTarget == Vector()) + { + return; + } + // Targeting code here. + if(sTargetMode == "TEST_LEVEL_TARGET") + { + int nLevel = ai_GetCharacterLevels(oTarget); + int nXPNeeded = StringToInt(Get2DAString("exptable", "XP", nLevel)); + int nXPToGive = nXPNeeded - GetXP(oTarget); + GiveXPToCreature(oTarget, nXPToGive); + ai_SendMessages(GetName(oTarget) + " has gained " + IntToString(nXPToGive) + " experience to gain 1 level.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "TEST_GOLD_TARGET") + { + GiveGoldToCreature(oTarget, 10000); + ai_SendMessages(GetName(oTarget) + " has gained 10,000 gold.", AI_COLOR_YELLOW, oPC); + } + else if(sTargetMode == "TEST_REST_TARGET") + { + ForceRest(oTarget); + ai_SendMessages(GetName(oTarget) + " has rested.", AI_COLOR_GREEN, oPC); + } + else if(sTargetMode == "TEST_HEAL_TARGET") + { + int nHeal = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget); + if(nHeal > 0) + { + effect eHeal = EffectHeal(nHeal); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget); + ai_SendMessages(GetName(oTarget) + " has been healed.", AI_COLOR_GREEN, oPC); + } + } + else if(sTargetMode == "TEST_ID_TARGET") SetIdentified(oTarget, !GetIdentified(oTarget)); + else if(sTargetMode == "TEST_CLEAR_TARGET") + { + ClearAllActions(TRUE, oTarget); + } + else if(sTargetMode == "TEST_KILL_TARGET") + { + effect eDmg = EffectDamage(10000); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oTarget); + ai_SendMessages(GetName(oTarget) + " has been killed.", AI_COLOR_RED, oPC); + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_KILL_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_KILL, MOUSECURSOR_NOKILL); + } + else if(sTargetMode == "TEST_REMOVE_TARGET") + { + SetIsDestroyable(TRUE, FALSE, FALSE, oTarget); + DestroyObject(oTarget); + ai_SendMessages(GetName(oTarget) + " has been removed!", AI_COLOR_RED, oPC); + } + else if(sTargetMode == "TEST_JUMP") + { + JumpToLocation(lLocation); + int nIndex; + object oAssociate; + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oPC); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, JumpToLocation(lLocation)); + } + for(nIndex = 1; nIndex < AI_MAX_HENCHMAN; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, JumpToLocation(lLocation)); + } + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_JUMP"); + EnterTargetingMode(oPC, OBJECT_TYPE_TILE, MOUSECURSOR_TRANSITION, MOUSECURSOR_NOWALK); + } + else if(sTargetMode == "TEST_KILL_AREA") + { + effect eDmg = EffectDamage(10000); + object oKill = GetFirstObjectInShape(SHAPE_SPHERE, 6.67, lLocation, FALSE); + while(oKill != OBJECT_INVALID) + { + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDmg, oKill); + oKill = GetNextObjectInShape(SHAPE_SPHERE, 6.67, lLocation, FALSE); + } + } + } + // Run all non-targeting code here, usually NUI events. + else + { + object oPC = NuiGetEventPlayer(); + int nToken = NuiGetEventWindow(); + string sEvent = NuiGetEventType(); + string sElem = NuiGetEventElement(); + int nIndex = NuiGetEventArrayIndex(); + //string sWndId = NuiGetWindowId(oPC, nToken); + //********************************************************************** + //if(GetLocalInt(oPC, AI_NO_NUI_SAVE)) return; + if(sEvent == "click") + { + if(sElem == "btn_level") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_LEVEL_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_gold") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_GOLD_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE); + } + else if(sElem == "btn_rest") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_REST_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE); + } + else if(sElem == "btn_heal") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_HEAL_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_HEAL, MOUSECURSOR_NOHEAL); + } + else if(sElem == "btn_id_item") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_ID_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_ITEM, MOUSECURSOR_HEAL, MOUSECURSOR_NOHEAL); + } + else if(sElem == "btn_clear") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_CLEAR_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_MAGIC, MOUSECURSOR_NOMAGIC); + } + else if(sElem == "btn_kill") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_KILL_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_KILL, MOUSECURSOR_NOKILL); + } + else if(sElem == "btn_remove") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_REMOVE_TARGET"); + EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE | + OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM | + OBJECT_TYPE_PLACEABLE, MOUSECURSOR_KILL, MOUSECURSOR_NOKILL); + } + else if(sElem == "btn_jump") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_JUMP"); + EnterTargetingMode(oPC, OBJECT_TYPE_TILE, MOUSECURSOR_TRANSITION, MOUSECURSOR_NOWALK); + } + else if(sElem == "btn_kill_area") + { + // Set this variable on the player so PEPS can run the targeting script for this plugin. + SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_test"); + // Set Targeting variables. + SetLocalObject(oPC, AI_TARGET_ASSOCIATE, OBJECT_SELF); + SetLocalString(oPC, AI_TARGET_MODE, "TEST_KILL_AREA"); + SetEnterTargetingModeData(oPC, SPELL_TARGETING_SHAPE_SPHERE, 6.67, 0.0, 3); + EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_KILL, MOUSECURSOR_NOKILL); + } + } + else if(sEvent == "watch") + { + if(sElem == "txt_debug_creature") + { + } + } + } +} + + diff --git a/src/module/nss/pi_buffing.nss b/src/module/nss/pi_buffing.nss new file mode 100644 index 0000000..6ce454e --- /dev/null +++ b/src/module/nss/pi_buffing.nss @@ -0,0 +1,338 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pi_buffing +//////////////////////////////////////////////////////////////////////////////// + Executable plug in script for Philos Module Extentions. + + Database structure: + Name(string) Tag(String) Spells(Json) + Tag: Widget - 0 = x position, 1 = y position, 2 = On/Off, 3 = Locked + Tag: List (string) set to the list number selected 1,2,3, or 4. + Tag: List# is the list of spells for List number 1,2,3, or 4. + + UI to save a players buff spells to be cast after resting. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +const int BUFF_MAX_SPELLS = 50; +const string FB_NO_MONSTER_CHECK = "FB_NO_MONSTER_CHECK"; + +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +// Creates the table and initializes if it needs to. +void CheckBuffDataAndInitialize(object oPlayer, string sTag); +// sDataField should be one of the data fields for that table. +// sData is the string data to be saved. +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag); +// sDataField should be one of the data fields for that table. +// jData is the json data to be saved. +void SetBuffDatabaseJson(object oPlayer, string sDataField, json jData, string sTag); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +json GetBuffDatabaseJson(object oPlayer, string sDataField, string sTag); +// Creates the widget for buffing. +void PopupWidgetBuffGUIPanel(object oPC); + +void main() +{ + object oPC = OBJECT_SELF; + // Check to make sure the database is setup before we do anything. + CheckBuffDataAndInitialize(oPC, "menudata"); + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + if(JsonGetType(JsonArrayGet(jMenuData, 0)) == JSON_TYPE_NULL) + { + jMenuData = JsonArrayInsert(JsonArray(), JsonString("list1")); // 0 Spell List # + jMenuData = JsonArrayInsert(jMenuData, JsonFloat(0.0)); // 1 Main menu X pos. + jMenuData = JsonArrayInsert(jMenuData, JsonFloat(GetGUIHeightMiddle(oPC, 257.0))); // 2 Main menu Y pos. + jMenuData = JsonArrayInsert(jMenuData, JsonBool(FALSE)); // 3 Widget on/off + jMenuData = JsonArrayInsert(jMenuData, JsonBool(FALSE)); // 4 Widget Locked + jMenuData = JsonArrayInsert(jMenuData, JsonFloat(10.0)); // 5 Widget X pos. + jMenuData = JsonArrayInsert(jMenuData, JsonFloat(10.0)); // 6 Widget Y pos. + SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata"); + } + if(StartingUp(oPC)) return; + // Row 1 (Buttons) ********************************************************* 83 + json jRow = CreateButtonSelect(JsonArray(), "Save", "btn_save", 60.0f, 30.0f, "btn_save_tooltip"); + CreateButton(jRow, "Clear", "btn_clear", 60.0f, 30.0f, -1.0, "btn_clear_tooltip"); + CreateButton(jRow, "Buff", "btn_buff", 60.0f, 30.0f, -1.0, "btn_buff_tooltip"); + CreateButtonSelect(jRow, "List 1", "btn_list1", 60.0f, 30.0f); + CreateButtonSelect(jRow, "List 2", "btn_list2", 60.0f, 30.0f); + CreateButtonSelect(jRow, "List 3", "btn_list3", 60.0f, 30.0f); + CreateButtonSelect(jRow, "List 4", "btn_list4", 60.0f, 30.0f); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Buttons) ********************************************************* 121 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateCheckBox(jRow, "Buff Widget", "buff_widget", 110.0, 30.0f, "buff_widget_tooltip"); + jRow = CreateCheckBox(jRow, "Lock Widget", "lock_buff_widget", 110.0, 30.0f, "lock_buff_widget_tooltip"); + if(!AI_SERVER) + { + jRow = CreateCheckBox(jRow, "Don't Check for Monsters", "chbx_no_monster_check", 200.0, 30.0f, "chbx_no_monster_check_tooltip"); + } + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (List of Spells) ************************************************** 164 + // Create the button template for the List. + jRow = JsonArray(); + string sList = JsonGetString(JsonArrayGet(jMenuData, 0)); + int nCntr, nIndex; + string sCntr, sIndex; + json jSpell; + CheckBuffDataAndInitialize(oPC, sList); + json jSpells = GetBuffDatabaseJson(oPC, "spells", sList); + while(nCntr <= BUFF_MAX_SPELLS) + { + jSpell = JsonArrayGet(jSpells, nCntr); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + sIndex = IntToString(nIndex++); + jRow = CreateButtonImage(jRow, "", "btn_spell_" + sIndex, 35.0, 35.0, 0.0, "btn_spell_" + sIndex + "_tooltip"); + } + nCntr++; + } + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Get the window location to restore it from the database. + float fWidth = IntToFloat(nIndex) * 39; + if(fWidth < 470.0) fWidth = 470.0; + float fX = JsonGetFloat(JsonArrayGet(jMenuData, 1)); + float fY = JsonGetFloat(JsonArrayGet(jMenuData, 2)); + if(fX == 0.0f && fY == 0.0f) + { + fX = 0.0f; + fY = GetGUIHeightMiddle(oPC, 257.0); + } + // Set the layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPC, jLayout, "plbuffwin", "Fast Buffing Spells", + fX, fY, fWidth, 164.0, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_buffing"); + // Set the elements to show events. + int nSelected = GetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT) == "pc_savebuffs"; + NuiSetBind(oPC, nToken, "btn_save", JsonBool(nSelected)); + NuiSetBind(oPC, nToken, "btn_save_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_save_tooltip", JsonString(" Saves any spells cast on you or your associates.")); + NuiSetBind(oPC, nToken, "btn_clear", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_tooltip", JsonString(" Clears the current list of all saved spells.")); + NuiSetBind(oPC, nToken, "btn_buff", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_buff_tooltip", JsonString(" Casts the current list of saved spells.")); + if(sList == "list1") NuiSetBind (oPC, nToken, "btn_list1", JsonBool (TRUE)); + else NuiSetBind(oPC, nToken, "btn_list1", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_list1_event", JsonBool(TRUE)); + if(sList == "list2") NuiSetBind (oPC, nToken, "btn_list2", JsonBool (TRUE)); + else NuiSetBind(oPC, nToken, "btn_list2", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_list2_event", JsonBool(TRUE)); + if(sList == "list3") NuiSetBind (oPC, nToken, "btn_list3", JsonBool (TRUE)); + else NuiSetBind(oPC, nToken, "btn_list3", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_list3_event", JsonBool(TRUE)); + if(sList == "list4") NuiSetBind (oPC, nToken, "btn_list4", JsonBool (TRUE)); + else NuiSetBind (oPC, nToken, "btn_list4", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_list4_event", JsonBool(TRUE)); + int nValue = JsonGetInt(JsonArrayGet(jMenuData, 3)); + NuiSetBind(oPC, nToken, "buff_widget_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "buff_widget_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "buff_widget_check", TRUE); + string sText = " Creates a set of 4 buttons on the screen for quick buffing."; + NuiSetBind(oPC, nToken, "buff_widget_tooltip", JsonString(sText)); + nValue = JsonGetInt(JsonArrayGet(jMenuData, 4)); + NuiSetBind(oPC, nToken, "lock_buff_widget_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "lock_buff_widget_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "lock_buff_widget_check", TRUE); + sText = " Locks the buffing widget in place reducing its size."; + NuiSetBind(oPC, nToken, "lock_buff_widget_tooltip", JsonString(sText)); + if(!AI_SERVER) + { + NuiSetBind(oPC, nToken, "chbx_no_monster_check_event", JsonBool(TRUE)); + nValue = GetLocalInt(oPC, FB_NO_MONSTER_CHECK); + NuiSetBind(oPC, nToken, "chbx_no_monster_check_check", JsonBool(nValue)); + NuiSetBindWatch(oPC, nToken, "chbx_no_monster_check_check", TRUE); + sText = " Turns on/off checks for nearby monsters."; + NuiSetBind(oPC, nToken, "chbx_no_monster_check_tooltip", JsonString(sText)); + } + // Create buttons with spells listed. + int nSpell, nClass, nLevel, nMetamagic, nDomain; + string sName, sTargetName, sResRef; + nCntr = 0; + nIndex = 0; + while(nCntr <= BUFF_MAX_SPELLS) + { + jSpell = JsonArrayGet(jSpells, nCntr); + if(JsonGetType(jSpell) != JSON_TYPE_NULL) + { + nSpell = JsonGetInt(JsonArrayGet(jSpell, 0)); + nClass = JsonGetInt(JsonArrayGet(jSpell, 1)); + nLevel = JsonGetInt(JsonArrayGet(jSpell, 2)); + nMetamagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + sTargetName = JsonGetString(JsonArrayGet(jSpell, 5)); + sResRef = Get2DAString("spells", "IconResRef", nSpell); + sName = " " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sName += " (" + GetStringByStrRef(StringToInt(Get2DAString("classes", "Short", nClass))); + sName += " / " + IntToString (nLevel); + if(nMetamagic > 0) + { + if(nMetamagic == METAMAGIC_EMPOWER) sName += " / Empowered"; + else if(nMetamagic == METAMAGIC_EXTEND) sName += " / Extended"; + else if(nMetamagic == METAMAGIC_MAXIMIZE) sName += " / Maximized"; + else if(nMetamagic == METAMAGIC_QUICKEN) sName += " / Quickened"; + else if(nMetamagic == METAMAGIC_SILENT) sName += " / Silent"; + else if(nMetamagic == METAMAGIC_STILL) sName += " / Still"; + } + if(nDomain > 0) sName += " / Domain"; + sName += ") " + sTargetName; + sIndex = IntToString(nIndex++); + NuiSetBind(oPC, nToken, "btn_spell_" + sIndex + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_spell_" + sIndex + "_image", JsonString(sResRef)); + NuiSetBind(oPC, nToken, "btn_spell_" + sIndex + "_tooltip", JsonString(sName)); + } + nCntr++; + } + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_buffing")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Quick Buff")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("dm_appear")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata"); + int bWidgetOn = JsonGetInt(JsonArrayGet(jMenuData, 3)); + if(bWidgetOn) + { + PopupWidgetBuffGUIPanel(oPC); + ai_SendMessages("Buffing widget has been created.", AI_COLOR_YELLOW, oPC); + } + return TRUE; +} +void CreateBuffDataTable(object oPlayer) +{ + sqlquery sql = SqlPrepareQueryObject(oPlayer, + "CREATE TABLE IF NOT EXISTS BUFF_TABLE (" + + "name TEXT, " + + "tag TEXT, " + + "spells TEXT, " + + "PRIMARY KEY(name, tag));"); + SqlStep(sql); +} +void CheckBuffDataAndInitialize(object oPlayer, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' AND name=@tableName;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString (sql, "@tableName", "BUFF_TABLE"); + if(!SqlStep (sql)) CreateBuffDataTable(oPlayer); + sQuery = "SELECT name FROM BUFF_TABLE Where name = @name AND tag = @tag;"; + sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if(!SqlStep(sql)) + { + sQuery = "INSERT INTO BUFF_TABLE(name, tag, spells) " + + "VALUES (@name, @tag, @spells);"; + sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + SqlBindJson(sql, "@spells", JsonArray()); + SqlStep(sql); + } +} +void SetBuffDatabaseString(object oPlayer, string sDataField, string sData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@data", sData); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + SqlStep(sql); +} +string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if(SqlStep(sql)) return SqlGetString(sql, 0); + else return ""; +} +void SetBuffDatabaseJson (object oPlayer, string sDataField, json jData, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "UPDATE BUFF_TABLE SET " + sDataField + " = @data WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindJson(sql, "@data", jData); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + SqlStep(sql); +} +json GetBuffDatabaseJson(object oPlayer, string sDataField, string sTag) +{ + string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer, TRUE))); + string sQuery = "SELECT " + sDataField + " FROM BUFF_TABLE WHERE name = @name AND tag = @tag;"; + sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery); + SqlBindString(sql, "@name", sName); + SqlBindString(sql, "@tag", sTag); + if(SqlStep(sql)) return SqlGetJson(sql, 0); + else return JsonArray(); +} +void PopupWidgetBuffGUIPanel(object oPC) +{ + // Set window to not save until it has been created. + SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // Row 1 (buttons)********************************************************** + json jRow = JsonArray(); + CreateButtonImage(jRow, "ir_level1", "btn_one", 35.0f, 35.0f, 0.0); + CreateButtonImage(jRow, "ir_level2", "btn_two", 35.0f, 35.0f, 0.0); + CreateButtonImage(jRow, "ir_level3", "btn_three", 35.0f, 35.0f, 0.0); + CreateButtonImage(jRow, "ir_level4", "btn_four", 35.0f, 35.0f, 0.0); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + json jWidget = GetBuffDatabaseJson(oPC, "spells", "menudata"); + int bAIBuffWidgetLock = JsonGetInt(JsonArrayGet(jWidget, 4)); + // Get the window location to restore it from the database. + float fX = JsonGetFloat(JsonArrayGet(jWidget, 5)); + float fY = JsonGetFloat(JsonArrayGet(jWidget, 6)); + if(fX == 0.0f && fY == 0.0f) + { + fX = 10.0f; + fY = 10.0f; + } + if(bAIBuffWidgetLock) + { + fX = fX + 4.0f; + fY = fY + 45.0f; + } + // Set the layout of the window. + json jLayout = NuiCol (jCol); + int nToken; + if(bAIBuffWidgetLock) nToken = SetWindow(oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_buffing"); + else nToken = SetWindow(oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_buffing"); + // Set event watches for window inspector and save window location. + //NuiSetBindWatch(oPC, nToken, "collapsed", TRUE); + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + // Set the buttons to show events. + //NuiSetBind (oPC, nToken, "btn_one", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_one_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_two", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_two_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_three", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_three_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_four", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_four_event", JsonBool(TRUE)); +} + diff --git a/src/module/nss/pi_crafting.nss b/src/module/nss/pi_crafting.nss new file mode 100644 index 0000000..3fa9775 --- /dev/null +++ b/src/module/nss/pi_crafting.nss @@ -0,0 +1,717 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pi_crafting +//////////////////////////////////////////////////////////////////////////////// + Executable plug in script for Philos Module Extentions + + Crafting UI for players items. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "0i_items" +#include "nw_inc_gff" +const string CRAFT_JSON = "CRAFT_JSON"; +const string CRAFT_COOL_DOWN = "CRAFT_COOL_DOWN"; +const string CRAFT_ITEM_SELECTION = "CRAFT_ITEM_SELECTION"; +const string CRAFT_MATERIAL_SELECTION = "CRAFT_MATERIAL_SELECTION"; +const string CRAFT_MODEL_SELECTION = "CRAFT_MODEL_SELECTION"; +const string CRAFT_COLOR_PALLET = "CRAFT_COLOR_PALLET"; +const string CRAFT_LEFT_PART_COLOR = "CRAFT_LEFT_PART_COLOR"; +const string CRAFT_ALL_COLOR = "CRAFT_ALL_COLOR"; +const string CRAFT_RIGHT_PART_COLOR = "CRAFT_RIGHT_PART_COLOR"; +const string CRAFT_TARGET = "CRAFT_TARGET"; +// Tag used in lighting effects. +const string CRAFT_HIGHLIGHT = "CRAFT_HIGHLIGHT"; +const string CRAFT_ULTRALIGHT = "CRAFT_ULTRALIGHT"; + +json CreateItemCombo(object oPC, json jRow, string sComboBind); +json CreateModelCombo(object oPC, object oTarget, json jRow, string sComboBind); +json CreateMaterialCombo(object oPC, json jRow, string sComboBind); +// Sets the material buttons for use. +// nMaterial 0,1 Cloth 2,3 Leather 4,5 Metal -1 None. +void SetMaterialButtons(object oPC, int nToken, int nMaterial); +// Returns the correct item based on the crafting menu selected item. +object GetSelectedItem(object oTarget, int nItemSelected); +int GetArmorModelSelected(object oPC); +// Returns True if oItem, nPart has a per part color for sSide. +int GetHasPartColor(object oItem, int nPart, string sSide); +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +void main() +{ + object oPC = OBJECT_SELF; + object oTarget = GetLocalObject(oPC, CRAFT_TARGET); + if(oTarget == OBJECT_INVALID) oTarget = oPC; + if(StartingUp(oPC)) return; + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + // Row 1 (Object Name)****************************************************** 508 / 83 + json jRow = CreateTextEditBox(JsonArray(), "plc_hold_bind", "txt_item_name", 50, FALSE, 486.0f, 30.0f); // 419 + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Object Name)****************************************************** 508 / 121 + jRow = JsonArray(); + if(!AI_SERVER) jRow = CreateButton(jRow, "Information", "btn_info", 160.0f, 30.0f, -1.0, "btn_info_tooltip"); + else + { + if(GetIsDM(oTarget)) + { + jRow = CreateButton(jRow, "Information", "btn_info", 160.0f, 30.0f, -1.0, "btn_info_tooltip"); + } + else jRow = JsonArrayInsert(jRow, NuiSpacer()); + } + jRow = CreateButton(jRow, "Wardrobe", "btn_wardrobe", 158.0f, 30.0f, -1.0, "btn_wardrobe_tooltip"); + jRow = CreateButtonSelect(jRow, "Add Light", "btn_highlight", 160.0f, 30.0f, "btn_highlight_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Object Name)****************************************************** 508 / 159 + jRow = CreateButton(JsonArray(), "Save", "btn_save", 160.0f, 30.0f, -1.0, "btn_save_tooltip"); + jRow = CreateButton(jRow, "Select Target", "btn_select_target", 158.0f, 30.0f); + jRow = CreateButton(jRow, "", "btn_cancel", 160.0f, 30.0f, -1.0, "btn_cancel_tooltip"); + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (labels)*********************************************************** 508 / 177 + jRow = CreateLabel(JsonArray(), "Model", "module_title", 143.0f, 10.0f); + jRow = CreateLabel(jRow, "Color", "color_title", 339.0f, 10.0f); + jRow = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 (groups) + // Row 51 (title)*********************************************************** 508 / 195 / 18 + json jGroupRow = CreateLabel(JsonArray(), "Item", "item__cmb_title", 128.0f, 10.0f); + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + // Row 52 (combo)*********************************************************** 508 / 233 / 56 + jGroupRow = CreateItemCombo(oPC, JsonArray(), "item_combo"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 53 (title)*********************************************************** 508 / 251 / 74 + jGroupRow = CreateLabel(JsonArray(), "Model", "model_cmb_title",128.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 54 (combo)*********************************************************** 508 / 289 / 112 + jGroupRow = CreateModelCombo(oPC, oTarget, JsonArray(), "model_combo"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 55 (title)*********************************************************** 508 / 307 / 120 + jGroupRow = CreateLabel(JsonArray(), "", "top_title",128.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 56 (top)************************************************************* 508 / 355 / 168 + jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_t", 40.0f, 40.0f); + // Removed TextEditBox for mobile + jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_t", 3, FALSE, 40.0, 40.0); + //CreateLabel(jGroupRow, "", "txt_model_number_t", 40.0, 40.0); + jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_t", 40.0f, 40.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 57 (title)*********************************************************** 508 / 373 / 186 + jGroupRow = CreateLabel(JsonArray(), "", "middle_title",128.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 58 (middle)********************************************************** 508 / 421 /234 + jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_m", 40.0f, 40.0f); + // Removed TextEditBox for mobile + jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_m", 3, FALSE, 40.0, 40.0); + //CreateLabel(jGroupRow, "", "txt_model_number_m", 40.0, 40.0); + jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_m", 40.0f, 40.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 59 (title)*********************************************************** 508 / 439 / 252 + jGroupRow = CreateLabel(JsonArray(), "", "bottom_title",128.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 510 (bottom)********************************************************* 508 / 487 /300 + jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_b", 40.0f, 40.0f); + // Removed TextEditBox for mobile + jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_b", 3, FALSE, 40.0, 40.0); + //CreateLabel(jGroupRow, "", "txt_model_number_b", 40.0, 40.0); + jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_b", 40.0f, 40.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 511 (blank spacer) + jGroupRow = CreateLabel(JsonArray(), "", "blank_space",128.0f, 20.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 512 (light)********************************************************** 508 / 487 /300 + jGroupRow = CreateButtonSelect(JsonArray(), "Randomize", "btn_randomize", 128.0f, 30.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupCol = JsonArrayInsert(jGroupCol, NuiSpacer()); + jRow = JsonArrayInsert(JsonArray(), NuiHeight(NuiWidth(NuiGroup(NuiCol(jGroupCol)), 143.0), 442.0)); + // Make the Color Group. + // Row 550 (groups)********************************************************* 508 / 361 / 184 + json jImage = NuiEnabled(NuiId(NuiImage(NuiBind("color_pallet_image"), JsonInt(0), JsonInt(0), JsonInt(1)), "color_pallet"), NuiBind("color_pallet_event")); + jImage = NuiWidth(jImage, 320.0); // 256 + 64 + jImage = NuiHeight(jImage, 220.0); // 176 + 44 + jImage = NuiTooltip(jImage, NuiBind("color_pallet_tooltip")); + json jIndicator = JsonArrayInsert(JsonArray(), NuiDrawListRect(JsonBool(TRUE), NuiColor(255,255,255), JsonBool(FALSE), JsonFloat(2.0), NuiBind("color_pallet_pointer"))); + jImage = NuiDrawList(jImage, JsonBool(FALSE), jIndicator); + jGroupRow = JsonArrayInsert(JsonArray(), jImage); + jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + // Row 551 (groups)********************************************************* 508 / 379 /202 + jGroupRow = CreateLabel(JsonArray(), "Part To Color", "lbl_color_parts", 320.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 552 (groups)********************************************************* 508 / 417 /240 + jGroupRow = CreateButtonSelect(JsonArray(), "Right", "btn_right_part_color", 98.0, 30.0, "btn_right_part_color_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "All", "btn_all_color", 98.0, 30.0, "btn_all_color_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "Left", "btn_left_part_color", 98.0, 30.0, "btn_left_part_color_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 553 (groups)********************************************************* 508 / 435 / 258 + jGroupRow = CreateLabel(JsonArray(), "Part Color To Reset", "lbl_reset_parts", 320.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 554 (groups)********************************************************* 508 / 473 /296 + jGroupRow = CreateButton(JsonArray(), "Right", "btn_right_part_reset", 98.0, 30.0, -1.0, "btn_right_part_reset_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButton(jGroupRow, "All", "btn_all_reset", 50.0, 30.0, -1.0, "btn_all_reset_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButton(jGroupRow, "Left", "btn_left_part_reset", 98.0, 30.0, -1.0, "btn_left_part_reset_tooltip"); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 555 (groups)********************************************************* 508 / 491 / 314 + jGroupRow = CreateLabel(JsonArray(), "Material to Color", "lbl_material_color", 320.0f, 10.0f); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 556 (groups)********************************************************* 508 / 529 /352 + jGroupRow = CreateButtonSelect(JsonArray(), "Cloth 1", "btn_material_0", 98.0, 30.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "Leather 1", "btn_material_2", 98.0, 30.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "Metal 1", "btn_material_4", 98.0, 30.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Row 557 (groups)********************************************************* 508 / 567 / 390 + jGroupRow = CreateButtonSelect(JsonArray(), "Cloth 2", "btn_material_1", 98.0, 30.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "Leather 2", "btn_material_3", 98.0, 30.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButtonSelect(jGroupRow, "Metal 2", "btn_material_5", 98.0, 30.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupCol = JsonArrayInsert(jGroupCol, NuiSpacer()); + jRow = JsonArrayInsert(jRow, NuiHeight(NuiWidth(NuiGroup(NuiCol(jGroupCol)), 339.0), 442.0)); // 275 398 + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + json jLayout = NuiCol(jCol); + // Get the window location to restore it from the database. + json jGeometry = JsonObjectGet(jCraft, "CRAFT_MENU"); + float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); + float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); + string sPCWindow; + int nToken = SetWindow(oPC, jLayout, "crafting_nui", "Crafting", + fX, fY, 508.0, 700.0, FALSE, FALSE, FALSE, FALSE, TRUE, "pe_crafting"); // 444 645 + // Set all binds, events, and watches. + NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE); + int nItem = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + object oItem = GetSelectedItem(oTarget, nItem); + // Row 1 + NuiSetBind(oPC, nToken, "txt_item_name", JsonString(GetName(oItem))); + NuiSetBind(oPC, nToken, "txt_item_name_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "txt_item_name", TRUE); + // Row 2 + NuiSetBind(oPC, nToken, "btn_info_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_info_tooltip", JsonString(" Look at and change item information")); + NuiSetBind(oPC, nToken, "btn_wardrobe_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_wardrobe_tooltip", JsonString(" Use your wardrobe to save/load item appearances")); + int nLight = GetLocalInt(oPC, CRAFT_HIGHLIGHT) + GetLocalInt(oPC, CRAFT_ULTRALIGHT); + NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(nLight)); + NuiSetBind(oPC, nToken, "btn_highlight_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_highlight_tooltip", JsonString(" Left click for White light, Right click for Ultravision")); + // Row 3 + NuiSetBind(oPC, nToken, "btn_save_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_save_tooltip", JsonString(" Save current changes")); + NuiSetBind(oPC, nToken, "btn_select_target_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cancel_label", JsonString("Exit")); + NuiSetBind(oPC, nToken, "btn_cancel_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cancel_tooltip", JsonString(" Exit the crafting menu")); + // Row 4 Labels. + // Row 5 Groups. + // Row 51 title. + // Row 52 + NuiSetBind(oPC, nToken, "item_combo_selected", JsonInt(nItem)); + NuiSetBind(oPC, nToken, "item_combo_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "item_combo_selected", TRUE); + // Row 53 title. + // Row 54 + int nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION)); + if(nItem == 1 || nItem == 2 || nItem == 4) + { + if(GetHiddenWhenEquipped(oItem)) nSelected = 1; + else nSelected = 0; + } + NuiSetBind(oPC, nToken, "model_combo_selected", JsonInt (nSelected)); + NuiSetBind(oPC, nToken, "model_combo_event", JsonBool (TRUE)); + NuiSetBindWatch(oPC, nToken, "model_combo_selected", TRUE); + // Row 55, 56, 57 titles + // Row 58 top, 59 middle, 510 bottom + string sModelTop, sModelMiddle, sModelBottom; + // Model Group + if(ai_GetIsWeapon(oItem)) + { + int nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 0); + int nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 0); + int nModelNumber = (nModel * 10) + nColor; + sModelTop = IntToString(nModelNumber); + nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 1); + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 1); + nModelNumber = (nModel * 10) + nColor; + sModelMiddle = IntToString(nModelNumber); + nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 2); + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 2); + nModelNumber = (nModel * 10) + nColor; + sModelBottom = IntToString(nModelNumber); + // Row 55 + NuiSetBind(oPC, nToken, "top_title_label", JsonString("Top")); + // Row 56 + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE)); + // Row 57 + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Middle")); + // Row 58 + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + // Row 59 + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Bottom")); + // Row 510 + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom)); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE)); + // Row 511 + NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected weapon")); + } + // Armor and clothing + else if(nItem == 0) + { + nSelected = GetArmorModelSelected(oPC); + // These models only have one side so make sure we are not linked. + if (nSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + // Row 55 + NuiSetBind(oPC, nToken, "top_title_label", JsonString("")); + // Row 56 + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_name_t", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE)); + // Row 57 + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model")); + // Row 58 + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + // Row 59 + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("")); + // Row 510 + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE)); + } + else + { + sModelTop = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + if(nSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nSelected--; + else nSelected++; + sModelBottom = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected)); + // Row 55 + NuiSetBind(oPC, nToken, "top_title_label", JsonString("Right")); + // Row 56 + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE)); + // Row 57 + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Right & Left")); + // Row 58 + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelTop)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + // Row 59 + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Left")); + // Row 510 + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom)); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE)); + } + // Row 511 + NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected armor")); + } + // Shields, Cloaks, and Helmets. + else + { + sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0)); + // Row 55 + NuiSetBind(oPC, nToken, "top_title_label", JsonString("")); + // Row 56 + //NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE)); + // Row 57 + NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model")); + // Row 58 + //NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle)); + NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE)); + // Row 59 + NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("")); + // Row 510 + //NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString("")); + NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE)); + // Row 511 + NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected item")); + } + // Color Group + if(ai_GetIsWeapon(oItem) || ai_GetIsShield(oItem)) + { + // Need to disable the color widgets. + // Row 511 + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString("gui_pal_tattoo")); + NuiSetBind(oPC, nToken, "color_pallet_image_event", JsonBool(FALSE)); + // Row 512 - Label Part to Color + // Row 5l3 + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 515 + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + // Row 516 - Label Material to Color + // Row 517 + NuiSetBind(oPC, nToken, "btn_material_0", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_2", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_4", JsonBool(FALSE)); + // Row 518 + NuiSetBind(oPC, nToken, "btn_material_1", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_3", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_material_5", JsonBool(FALSE)); + SetMaterialButtons(oPC, nToken, -1); + } + // Armor and clothing + else if(nItem == 0) + { + // Row 511 + string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET); + if(sColorPallet == "") sColorPallet = "gui_pal_tattoo"; + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + int nModelSelected = GetArmorModelSelected(oPC); + // Row 511 + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet)); + NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel")); + int nSelectedRight, nSelectedAll, nSelectedLeft; + string sColorAll = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected)); + // These models only have one side so make sure we are not linked. + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK || + nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO || + nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT || + nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS || + nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE) + { + // Row 512 - Label Part to Color + // Row 5l3 + int nPartColor = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)); + if(!nSelectedRight && nPartColor) + { + nSelectedRight = TRUE; + nSelectedLeft = FALSE; + } + nSelectedAll = !nSelectedRight; + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(nSelectedAll)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedAll = nSelectedRight; + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + } + else + { + // Row 512 - Label Part to Color + // Row 5l3 + int nPartColor = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)); + if(!nSelectedRight && nPartColor) + { + nSelectedRight = TRUE; + nSelectedLeft = FALSE; + } + else + { + nPartColor = GetHasPartColor(oItem, nModelSelected, "Left"); + nSelectedLeft = JsonGetInt(JsonObjectGet(jCraft, CRAFT_LEFT_PART_COLOR)); + if(!nSelectedLeft && nPartColor) + { + nSelectedLeft = TRUE; + nSelectedRight = FALSE; + } + } + nSelectedAll = !nSelectedRight && !nSelectedLeft; + jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonBool(nSelectedLeft)); + jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(nSelectedAll)); + jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(nSelectedLeft)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(TRUE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right"); + nSelectedLeft = GetHasPartColor(oItem, nModelSelected, "Left"); + nSelectedAll = nSelectedRight || nSelectedLeft; + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight)); + NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(nSelectedLeft)); + } + int nColor; + if(!JsonGetInt(NuiGetBind(oPC, nToken, "btn_all_color"))) + { + int nModelSelected = GetArmorModelSelected(oPC); + if(!JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR))) + { + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--; + else nModelSelected++; + } + int nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected; + nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex); + } + else nColor = 255; + if(nColor == 255) nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected); + float fPointX = IntToFloat((nColor - ((nColor / 16) * 16)) * 20); + float fPointY = IntToFloat((nColor / 16) * 20); + NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(fPointX, fPointY, 20.0, 20.0)); + // Row 516 - Label Material to Color + // Row 517 & 518 + NuiSetBind(oPC, nToken, "btn_right_part_color_tooltip", JsonString(" Select the right part to be uniquely colored")); + NuiSetBind(oPC, nToken, "btn_all_color_tooltip", JsonString(" Select all parts to be colored")); + NuiSetBind(oPC, nToken, "btn_left_part_color_tooltip", JsonString(" Select the left part to be uniquely colored")); + NuiSetBind(oPC, nToken, "btn_right_part_reset_tooltip", JsonString(" Clears the right part's unique color")); + NuiSetBind(oPC, nToken, "btn_all_reset_tooltip", JsonString(" Clears all parts unique colors")); + NuiSetBind(oPC, nToken, "btn_left_part_reset_tooltip", JsonString(" Clears the left part's unique color")); + nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + SetMaterialButtons(oPC, nToken, nSelected); + SetLocalJson(oPC, CRAFT_JSON, jCraft); + } + // Cloaks and Helmets. + else + { + // Row 511 + string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET); + if(sColorPallet == "") sColorPallet = "gui_pal_tattoo"; + int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + int nModelSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION)); + int nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected); + float fPointX = IntToFloat((nColor - ((nColor / 16) * 16)) * 20); + float fPointY = IntToFloat((nColor / 16) * 20); + NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(fPointX, fPointY, 20.0, 20.0)); + NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet)); + NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel")); + // Row 512 - Label Part to Color + // Row 5l3 + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE)); + // Row 514 - Label Part Color to Reset + // Row 5l5 + NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE)); + //NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE)); + // Row 516 - Label Material to Color + // Row 517 & 518 + nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION)); + SetMaterialButtons(oPC, nToken, nSelected); + } + // Lets make sure we clean up any cool down variables. + //DeleteLocalInt(oPC, CRAFT_COOL_DOWN); +} +json CreateItemCombo(object oPC, json jRow, string sComboBind) +{ + int nCnt; + // Create the list. + json jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Armor", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Cloak", 1)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Headgear", 2)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Right hand", 3)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Left hand", 4)); + return CreateCombo(jRow, jCombo, sComboBind, 128.0, 40.0); +} +json CreateModelCombo(object oPC, object oTarget, json jRow, string sComboBind) +{ + float fFacing = GetFacing(oTarget); + json jCombo, jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION)); + // Create the list. + // Armor. + if(nSelected == 0) + { + fFacing += 180.0f; + if (fFacing > 359.0) fFacing -=359.0; + AssignCommand(oPC, SetCameraFacing(fFacing, 4.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST)); + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Neck", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Shoulder", 1)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Bicep", 2)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Forearm", 3)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Hand", 4)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Torso", 5)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Belt", 6)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Pelvis", 7)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Thigh", 8)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Shin", 9)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Foot", 10)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Robe", 11)); + } + // Cloak. + else if(nSelected == 1) + { + if(fFacing > 359.0) fFacing -=359.0; + AssignCommand (oPC, SetCameraFacing(fFacing, 4.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST)); + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Cloak", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1)); + } + // Headgear. + else if (nSelected == 2) + { + fFacing += 180.0f; + if(fFacing > 359.0) fFacing -=359.0; + AssignCommand(oPC, SetCameraFacing(fFacing, 2.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST)); + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Headgear", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1)); + } + // Weapon. + else if (nSelected == 3) + { + // If they are changing a bow then face the opposite side. + object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); + int nBaseItemType = GetBaseItemType(oItem); + if(nBaseItemType == BASE_ITEM_LONGBOW || nBaseItemType == BASE_ITEM_SHORTBOW) fFacing -= 90.00; + // This will make the camera face a melee weapon. + else fFacing += 90.0; + if(fFacing > 359.0) fFacing -=359.0; + AssignCommand(oPC, SetCameraFacing(fFacing, 3.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST)); + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Weapon", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Acidic", 1)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Frost", 2)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Electric", 3)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Unholy", 4)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Flaming", 5)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Holy", 6)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Sonic", 7)); +} + // Weapon/Shield. + else if(nSelected == 4) + { + fFacing += 270.0f; + if(fFacing > 359.0) fFacing -=359.0; + AssignCommand(oPC, SetCameraFacing(fFacing, 3.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST)); + object oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC); + if(ai_GetIsShield(oItem)) + { + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Shield", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1)); + } + else + { + jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Weapon", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Acidic", 1)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Frost", 2)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Electric", 3)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Unholy", 4)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Flaming", 5)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Holy", 6)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Sonic", 7)); + } + } + return CreateCombo(jRow, jCombo, sComboBind, 128.0, 40.0); +} +void SetMaterialButtons(object oPC, int nToken, int nMaterial) +{ + int nIndex, bBool, bUseable; + string sIndex; + if(nMaterial > -1) bUseable = TRUE; + for(nIndex = 0;nIndex < 6;nIndex++) + { + if(nIndex == nMaterial) bBool = TRUE; + else bBool = FALSE; + sIndex = IntToString(nIndex); + NuiSetBind(oPC, nToken, "btn_material_" + sIndex + "_event", JsonBool(bUseable)); + NuiSetBind(oPC, nToken, "btn_material_" + sIndex, JsonBool(bBool)); + } +} +object GetSelectedItem(object oTarget, int nItemSelected) +{ + if(nItemSelected == 0) return GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget); + else if(nItemSelected == 1) return GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget); + else if(nItemSelected == 2) return GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget); + else if(nItemSelected == 3) return GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + else if(nItemSelected == 4) return GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget); + return OBJECT_INVALID; +} +int GetArmorModelSelected(object oPC) +{ + json jCraft = GetLocalJson(oPC, CRAFT_JSON); + int nModelSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION)); + if(nModelSelected == 0) return ITEM_APPR_ARMOR_MODEL_NECK; + if(nModelSelected == 1) return ITEM_APPR_ARMOR_MODEL_RSHOULDER; + if(nModelSelected == 2) return ITEM_APPR_ARMOR_MODEL_RBICEP; + if(nModelSelected == 3) return ITEM_APPR_ARMOR_MODEL_RFOREARM; + if(nModelSelected == 4) return ITEM_APPR_ARMOR_MODEL_RHAND; + if(nModelSelected == 5) return ITEM_APPR_ARMOR_MODEL_TORSO; + if(nModelSelected == 6) return ITEM_APPR_ARMOR_MODEL_BELT; + if(nModelSelected == 7) return ITEM_APPR_ARMOR_MODEL_PELVIS; + if(nModelSelected == 8) return ITEM_APPR_ARMOR_MODEL_RTHIGH; + if(nModelSelected == 9) return ITEM_APPR_ARMOR_MODEL_RSHIN; + if(nModelSelected == 10) return ITEM_APPR_ARMOR_MODEL_RFOOT; + return ITEM_APPR_ARMOR_MODEL_ROBE; +} +int GetHasPartColor(object oItem, int nPart, string sSide) +{ + json jItem = ObjectToJson(oItem); + string sPartName = "APart_"; + if(sSide == "Left") + { + // Note: Right Thigh and Left Thigh are backwards so this fixes that! + if (nPart == ITEM_APPR_ARMOR_MODEL_RTHIGH) nPart--; + else nPart++; + } + sPartName += IntToString(nPart) + "_Col_"; + int nPartColor = JsonGetInt(GffGetByte(jItem, sPartName + "0")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "1")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "2")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "3")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "4")); + nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "5")); + return nPartColor; +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_crafting")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Item Crafting")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("isk_x2cweap")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + return TRUE; +} + diff --git a/src/module/nss/pi_debug.nss b/src/module/nss/pi_debug.nss new file mode 100644 index 0000000..6555882 --- /dev/null +++ b/src/module/nss/pi_debug.nss @@ -0,0 +1,200 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: pi_debug + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Plugin for debugging. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "0i_player_target" +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +void main() +{ + object oPC = OBJECT_SELF; + if(StartingUp(oPC)) return; + // Set window to not save until it has been created. + //SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + //DelayCommand (0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + string sText = " [Single player]"; + if(AI_SERVER) sText = " [Server]"; + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 500 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, PHILOS_VERSION + sText, "lbl_version", 470.0f, 20.0f, NUI_HALIGN_CENTER); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 129 + sText = "Module: " + GetModuleName() + " [" + GetTag(GetModule()) + "]"; + jRow = CreateLabel(JsonArray(), sText, "lbl_module_name", 470.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 500 / 101 + sText = "Monster AI (nw_c2_default1): " + ResManGetAliasFor("nw_c2_default1", RESTYPE_NCS); + jRow = CreateLabel(JsonArray(), sText, "monster_1_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 ******************************************************************* 500 / 157 + sText = "Monster AI (j_ai_onheartbeat): " + ResManGetAliasFor("j_ai_onheartbeat", RESTYPE_NCS); + jRow = CreateLabel(JsonArray(), sText, "monster_2_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 5 ******************************************************************* 500 / 213 + sText = "Associate AI (nw_ch_ac1): " + ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS); + jRow = CreateLabel(JsonArray(), sText, "henchman_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 6 ******************************************************************* 500 / 241 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Set NPC's scripts", "btn_npc_scripts", 150.0f, 20.0f, -1.0, "btn_npc_scripts_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Set Reputations", "btn_set_reputation", 150.0f, 20.0f, -1.0, "btn_set_reputation_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear Party Rep.", "btn_clear_reputation", 150.0f, 20.0f, -1.0, "btn_clear_reputation_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 7 ******************************************************************* 500 / 269 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Display Target Info", "btn_info", 150.0f, 20.0f, -1.0, "btn_info_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Dump Object to Json", "btn_obj_json", 150.0f, 20.0f, -1.0, "btn_obj_json_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "List Object Variables", "btn_obj_var", 150.0f, 20.0f, -1.0, "btn_obj_var_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 8 ******************************************************************* 500 / 297 jRow = JsonArray(); + jRow = CreateButton(JsonArray(), "Delete Variable", "btn_delete_var", 115.0f, 25.0f, -1.0, "btn_delete_var_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Set Variable", "btn_set_var", 115.0f, 25.0f, -1.0, "btn_set_var_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Get Variable", "btn_get_var", 115.0f, 25.0f, -1.0, "btn_get_var_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + json jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("int", 0)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("float", 1)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("string", 2)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("object", 3)); + jCombo = JsonArrayInsert(jCombo, NuiComboEntry("location", 4)); + jRow = CreateCombo(jRow, jCombo, "cmb_var_type", 115.0, 25.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 9 ******************************************************************* 500 / 329 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "Name:", "lbl_name", 40.0f, 20.0f); + jRow = CreateTextEditBox(jRow, "sPlaceHolder", "txt_var_name", 40, FALSE, 425.0f, 20.0f, "txt_var_name_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 10 ******************************************************************* 500 / 357 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateLabel(jRow, "Value:", "lbl_value", 40.0f, 20.0f); + jRow = CreateTextEditBox(jRow, "sPlaceHolder", "txt_var_value", 40, FALSE, 425.0f, 20.0f, "txt_var_value_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 11 ******************************************************************* 500 / 385 + // Make the debug creature group. + // Group Row 1 ******************************************************************* 500 / 385 + json jGroupRow = CreateButton(JsonArray(), "Debug Creature", "btn_debug_creature", 120.0f, 20.0f, -1.0, "btn_debug_creature_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButton(jGroupRow, "Clear Event Scripts", "btn_clear_events", 150.0f, 20.0f, -1.0, "btn_clear_events_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupRow = CreateButton(jGroupRow, "Clear Debug", "btn_clear_debug", 120.0f, 20.0f, -1.0, "btn_clear_debug_tooltip"); + // Add group row to the group column. + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + float fHeight = 431.0; + // Group Row 2 ******************************************************************* 500 / --- + object oDebugCreature = GetLocalObject(oPC, "AI_RULE_DEBUG_CREATURE_OBJECT"); + if(GetIsObjectValid(oDebugCreature)) + { + string sScript = GetEventScript(oDebugCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT); + if(sScript == "nw_c2_default1") sText = GetName(oDebugCreature) + " is using monster AI scripts (" + sScript + ")."; + else if(sScript == "nw_ch_ac1") sText = GetName(oDebugCreature) + " is using associate AI scripts (" + sScript + ")."; + else if(sScript == "xx_pc_1_hb") sText = GetName(oDebugCreature) + " is using player AI scripts (" + sScript + ")."; + else if(sScript == "0e_id_events") sText = GetName(oDebugCreature) + " is using Infinite Dungeons AI scripts (" + sScript + ")."; + else if(sScript == "0e_prc_id_events") sText = GetName(oDebugCreature) + " is using PRC Infinite Dungeons AI scripts (" + sScript + ")."; + else sText = GetName(oDebugCreature) + " is using unknown AI scripts (" + sScript + ")."; + jGroupRow = CreateLabel(JsonArray(), sText, "debug_info", 455.0f, 20.0f, NUI_HALIGN_CENTER); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight = fHeight + 28; + } + // Group Row 3 ******************************************************************* 500 / --- + sText = GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE); + if(sText != "") sText = sText + " is sending AI debug to the log file."; + else sText = "Nothing is sending AI debug to the log file."; + jGroupRow = CreateLabel(JsonArray(), sText, "debug_log", 455.0f, 20.0f, NUI_HALIGN_CENTER); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + fHeight = fHeight + 28; + // Add group to the row. + jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, "pi_debug_nui", sName + " PEPS Debug Menu", + -1.0, -1.0, 500.0f, fHeight + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_debug"); + // Set all binds, events, and watches. + // Row 1 - Version label. + // Row 2 Module Name. + // Row 3 - 5 Script locations. + // Row 6 + NuiSetBind(oPC, nToken, "btn_npc_scripts_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_npc_scripts_tooltip", JsonString(" Forces NPC to use Philos AI scripts!")); + NuiSetBind(oPC, nToken, "btn_set_reputation_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_set_reputation_tooltip", JsonString(" Sets a creatures faction to neutral for all standard factions.")); + NuiSetBind(oPC, nToken, "btn_clear_reputation_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_reputation_tooltip", JsonString(" Clears the party's reputation with creature's faction.")); + // Row 7 + NuiSetBind(oPC, nToken, "btn_info_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_info_tooltip", JsonString(" Displays a target object's information to the log screen.")); + NuiSetBind(oPC, nToken, "btn_obj_json_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_obj_json_tooltip", JsonString(" Sends a Json Dump to the log file for the targeted object.")); + NuiSetBind(oPC, nToken, "btn_obj_var_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_obj_var_tooltip", JsonString(" Sends a list of variables for the targeted object.")); + // Row 8 + NuiSetBind(oPC, nToken, "btn_delete_var_tooltip", JsonString(" Delete the variable for the targeted object or Right click for the Module.")); + NuiSetBind(oPC, nToken, "btn_set_var_tooltip", JsonString(" Set the variable for the targeted object or Right click for the Module.")); + NuiSetBind(oPC, nToken, "btn_get_var_tooltip", JsonString(" Get the variable for the targeted object or Right click for the Module.")); + NuiSetBind(oPC, nToken, "cmb_var_type_event", JsonBool(TRUE)); + NuiSetBindWatch(oPC, nToken, "cmb_var_type_selected", TRUE); + // Row 9 + NuiSetBind(oPC, nToken, "txt_var_name_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "txt_var_name", TRUE); + NuiSetBind(oPC, nToken, "txt_var_name_tooltip", JsonString(" Name of the variable we are setting.")); + // Row 10 + NuiSetBind(oPC, nToken, "txt_var_value_event", JsonBool(TRUE)); + NuiSetBindWatch (oPC, nToken, "txt_var_value", TRUE); + NuiSetBind(oPC, nToken, "txt_var_value_tooltip", JsonString(" The value to set on the variable, Objects/Locations will need to be selected.")); + // Row 11 + NuiSetBind(oPC, nToken, "btn_debug_creature_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_debug_creature_tooltip", JsonString(" Sets target creature to send AI debug to the log file.")); + NuiSetBind(oPC, nToken, "btn_clear_events_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_events_tooltip", JsonString(" Sets a creature's event scripts to default.")); + NuiSetBind(oPC, nToken, "btn_clear_debug_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_debug_tooltip", JsonString(" Clears a creature from sending AI debug to the log file.")); +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_debug")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Debug Menu")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("dm_tagsearch")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + return TRUE; +} + diff --git a/src/module/nss/pi_forcerest.nss b/src/module/nss/pi_forcerest.nss new file mode 100644 index 0000000..dfabb34 --- /dev/null +++ b/src/module/nss/pi_forcerest.nss @@ -0,0 +1,70 @@ +#include "0i_menus" +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +void ai_UpdateAssociateWidget(object oMaster, object oAssociate, int nUIToken) +{ + if(nUIToken) NuiDestroy(oMaster, nUIToken); + ai_CreateWidgetNUI(oMaster, oAssociate); + if(oMaster != oAssociate) + { + nUIToken = NuiFindWindow(oMaster, "pc" + AI_WIDGET_NUI); + if(nUIToken) + { + NuiDestroy(oMaster, nUIToken); + ai_CreateWidgetNUI(oMaster, oMaster); + } + } +} +void main() +{ + object oPC = OBJECT_SELF; + if(StartingUp(oPC)) return; + ForceRest(oPC); + DeleteLocalInt(oPC, "HF_REST_LAST_TIME"); + int nIndex; + int nMaxHenchman = GetMaxHenchmen(); + object oAssociate; + for(nIndex = 1;nIndex <= nMaxHenchman; nIndex++) + { + oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + ForceRest(oAssociate); + DeleteLocalInt(oAssociate, "HF_REST_LAST_TIME"); + if(ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST)) + { + DelayCommand(1.0, ai_HenchmanCastDefensiveSpells(oAssociate, oPC)); + } + if(AI_HENCHMAN_WIDGET) + { + // Update widget for spell widget. + string sAssociateType = ai_GetAssociateType(oPC, oAssociate); + int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI); + if(nUIToken) DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate, nUIToken)); + else + { + if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType)) + { + DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate, 0)); + } + } + } + } +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_forcerest")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Force Rest")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("ir_rest")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + return TRUE; +} + diff --git a/src/module/nss/pi_henchmen.nss b/src/module/nss/pi_henchmen.nss new file mode 100644 index 0000000..5119039 --- /dev/null +++ b/src/module/nss/pi_henchmen.nss @@ -0,0 +1,209 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pi_henchmen +//////////////////////////////////////////////////////////////////////////////// + Executable plug in script for Philos Module Extentions. + + UI to save a players as Henchmen. +*/////////////////////////////////////////////////////////////////////////////// +#include "pinc_henchmen" +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +// Inserts base classes to an array for a combo box. +json JArrayInsertBaseClasses(); +void main() +{ + object oPC = OBJECT_SELF; + if(StartingUp(oPC)) return; + // Set window to not save until it has been created. + SetLocalInt (oPC, "AI_NO_NUI_SAVE", TRUE); + DelayCommand (0.5f, DeleteLocalInt (oPC, "AI_NO_NUI_SAVE")); + // Row 1 (Buttons) ********************************************************* 775 / 73 + json jRow = CreateButtonSelect(JsonArray(), "Party 1", "btn_party1", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 2", "btn_party2", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 3", "btn_party3", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 4", "btn_party4", 90.0f, 20.0f); + jRow = CreateButtonSelect(jRow, "Party 5", "btn_party5", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 6", "btn_party6", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 7", "btn_party7", 90.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Party 8", "btn_party8", 90.0f, 20.0f); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 (Options)********************************************************** 775 / 101 + jRow = CreateButton(JsonArray(), "Clear Party", "btn_clear_party", 120.0f, 20.0f, -1.0, "btn_clear_party_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Party Join", "btn_join_party", 120.0f, 20.0f, -1.0, "btn_join_party_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButtonSelect(jRow, "Create NPC Henchman", "btn_npc_henchman", 200.0f, 20.0f, "btn_npc_henchman_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Save Party", "btn_save_party", 120.0f, 20.0f, -1.0, "btn_save_party_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Remove Party", "btn_remove_party", 120.0f, 20.0f, -1.0, "btn_remove_party_tooltip"); + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 (Names and List titles) ******************************************* 775 / 124 + jRow = CreateLabel(JsonArray(), "", "lbl_save_char", 150.0, 15.0, 0, 0); + jRow = CreateLabel(jRow, "", "lbl_save_list", 200.0, 15.0, 0, 0); + jRow = CreateLabel(jRow, "In game party", "lbl_game_list", 200.0, 15.0, 0, 0); + jRow = CreateLabel(jRow, "", "lbl_game_char", 150.0, 15.0, 0, 0); + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 4 (List Characters) ************************************************* 775 / 488 (364) + // Saved Characters for Party # + // ***** Adding character saved group next to the button list ************** + json jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateImage(jGroupRow, "", "img_saved_portrait", NUI_ASPECT_EXACTSCALED, NUI_HALIGN_CENTER, NUI_VALIGN_TOP, 128.0, 200.0, 0.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_saved_stats", 150.0, 15.0, 0, 0, 0.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_saved_classes", 150.0, 15.0, 0, 0, 0.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateButton(JsonArray(), "", "btn_saved_join", 75.0, 20.0); + jGroupRow = CreateButton(jGroupRow, "Remove", "btn_saved_remove", 75.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + //jGroupRow = JsonArray(); + //CreateButton(jGroupRow, "Edit", "btn_saved_edit", 150.0, 20.0); + //jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); + // Create the button template for the List. + json jButton = NuiId(NuiButton(NuiBind ("btns_saved_char")), "btn_saved_char"); + json jList = JsonArrayInsert(JsonArray (), NuiListTemplateCell(jButton, 170.0, TRUE)); + // Create the list with the template. + jRow = CreateList(jRow, jList, "btns_saved_char", 25.0, 200.0, 325.0); + // Current Characters. + // Create the button template for the List. + jButton = NuiId(NuiButton(NuiBind ("btns_cur_char")), "btn_cur_char"); + jList = JsonArrayInsert(JsonArray (), NuiListTemplateCell(jButton, 170.0, TRUE)); + // Create the list with the template. + jRow = CreateList(jRow, jList, "btns_cur_char", 25.0, 200.0, 325.0); + // ***** Adding character current group next to the button list ************ + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateImage(jGroupRow, "", "img_cur_portrait", NUI_ASPECT_EXACTSCALED, NUI_HALIGN_CENTER, NUI_VALIGN_TOP, 128.0, 200.0, 0.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_cur_stats", 150.0, 15.0, 0, 0, 0.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateLabel(JsonArray(), "", "lbl_cur_classes", 150.0, 15.0, 0, 0, 0.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateButton(JsonArray(), "", "btn_cur_save", 75.0, 20.0); + jGroupRow = CreateButton(jGroupRow, "Remove", "btn_cur_remove", 75.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jGroupRow = CreateButton(JsonArray(), "Edit", "btn_cur_edit", 150.0, 20.0); + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jRow = JsonArrayInsert(jRow, NuiGroup(NuiCol(jGroupCol))); + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Set the layout of the window. + json jLayout = NuiCol(jCol); + // Get the window location to restore it from the database. + CheckHenchmanDataAndInitialize(oPC, "0"); + json jData = GetHenchmanDbJson(oPC, "henchman", "0"); + json jGeometry = JsonObjectGet(jData, "henchman_nui"); + float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); + float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); + if(fX == 0.0 && fY == 0.0) + { + fX = -1.0; + fY = -1.0; + } + string sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow (oPC, jLayout, "henchman_nui", sName + " party", + fX, fY, 775.0, 488.0, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_henchmen"); + // Lets set MaxHenchman here. + if(GetMaxHenchmen() < 6) SetMaxHenchmen(6); + // Setup watch for saving location. + NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE); + // Set the elements to show events. + NuiSetBind(oPC, nToken, "btn_save_pc_event", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_current_party_event", JsonBool (TRUE)); + string sParty = GetHenchmanDbString(oPC, "henchname", "0"); + if(sParty == "") + { + SetHenchmanDbString(oPC, "henchname", "1", "0"); + sParty = "1"; + } + // Set the party # buttons. + int nIndex; + string sIndex; + for(nIndex = 1; nIndex < 9; nIndex++) + { + sIndex = IntToString(nIndex); + if(sParty == sIndex) NuiSetBind(oPC, nToken, "btn_party" + sIndex, JsonBool(TRUE)); + else NuiSetBind(oPC, nToken, "btn_party" + sIndex, JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_party" + sIndex + "_event", JsonBool (TRUE)); + } + NuiSetBind(oPC, nToken, "btn_npc_henchman_event", JsonBool(TRUE)); + string sText = " Select a creature to copy and have them join you."; + NuiSetBind(oPC, nToken, "btn_npc_henchman_tooltip", JsonString(sText)); + // ********** Saved Henchman in party # ********* + nIndex = 0; + int nSlot, nMaxHenchman = AI_MAX_HENCHMAN + 1; + json jButtons = JsonArray(); + string sFirstHenchman, sButtonText; + json jNPCs, jNPC; + // Add saved party members from sParty to the button list. + while(nIndex < nMaxHenchman) + { + sIndex = IntToString(nIndex); + sButtonText = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); + if(sButtonText != "") + { + jButtons = JsonArrayInsert(jButtons, JsonString(sButtonText)); + SetHenchmanDbString(oPC, "slot", sParty + IntToString(nSlot++), sParty + sIndex); + } + nIndex++; + } + // Add the buttons to the list. + NuiSetBind(oPC, nToken, "btns_saved_char", jButtons); + // Set up button lables for henchman. + NuiSetBind(oPC, nToken, "lbl_save_list_label", JsonString("Party Save " + sParty)); + AddSavedCharacterInfo(oPC, nToken, sParty); + // ********** Current Party ********* + NuiSetBind(oPC, nToken, "btn_current_party", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_party", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "lbl_save_char", JsonBool(TRUE)); + // Set up button labels for henchman. + NuiSetBind(oPC, nToken, "btn_join_save_label", JsonString("Save")); + nIndex = 0; + jButtons = JsonArray(); + object oPartyMember, oCharacter = OBJECT_INVALID; + // Add current party members to the button list. + while(nIndex < AI_MAX_HENCHMAN) + { + if(nIndex == 0) oPartyMember = oPC; + else oPartyMember = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oPartyMember != OBJECT_INVALID) jButtons = JsonArrayInsert(jButtons, JsonString(GetName(oPartyMember))); + else break; + nIndex++; + } + // Add the buttons to the list. + NuiSetBind(oPC, nToken, "btns_cur_char", jButtons); + AddCurrentCharacterInfo(oPC, nToken, sParty); +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_henchmen")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Henchmen Menu")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("dm_creator")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + return TRUE; +} + diff --git a/src/module/nss/pi_test.nss b/src/module/nss/pi_test.nss new file mode 100644 index 0000000..818da8c --- /dev/null +++ b/src/module/nss/pi_test.nss @@ -0,0 +1,103 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: pi_test + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Plugin for debugging. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "0i_player_target" +// Does startup check if the game has just been loaded. +int StartingUp(object oPC); +void main() +{ + object oPC = OBJECT_SELF; + if(StartingUp(oPC)) return; + string sText; + // Set window to not save until it has been created. + //SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE); + //DelayCommand (0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE)); + // ************************************************************************* Width / Height + // Row 1 ******************************************************************* 636 / 73 + json jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Level Up Creature", "btn_level", 150.0f, 20.0f, -1.0, "btn_level_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Gold for Creature", "btn_gold", 150.0f, 20.0f, -1.0, "btn_gold_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Force Rest Creature", "btn_rest", 150.0f, 20.0f, -1.0, "btn_rest_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "ID/UnID Item", "btn_id_item", 150.0f, 20.0f, -1.0, "btn_id_item_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 636 / 101 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Heal Creature", "btn_heal", 150.0f, 20.0f, -1.0, "btn_heal_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Clear Creature Actions", "btn_clear", 150.0f, 20.0f, -1.0, "btn_clear_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Kill Creature", "btn_kill", 150.0f, 20.0f, -1.0, "btn_kill_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Remove Object", "btn_remove", 150.0f, 20.0f, -1.0, "btn_remove_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Row 3 ******************************************************************* 636 / 101 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "Jump To", "btn_jump", 150.0f, 20.0f, -1.0, "btn_jump_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + jRow = CreateButton(jRow, "Kill In Area", "btn_kill_area", 150.0f, 20.0f, -1.0, "btn_kill_area_tooltip"); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + float fHeight = 129.0; + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + string sName = GetName(oPC); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow(oPC, jLayout, "pi_test_nui", sName + " PEPS Testing Menu", + -1.0, -1.0, 636.0f, fHeight + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_test"); + // Set all binds, events, and watches. + // Row 1 + NuiSetBind(oPC, nToken, "btn_level_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_tooltip", JsonString(" Give level to target creature.")); + NuiSetBind(oPC, nToken, "btn_gold_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_gold_tooltip", JsonString(" Give Gold to target creature.")); + NuiSetBind(oPC, nToken, "btn_rest_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_rest_tooltip", JsonString(" Force rest target creature.")); + NuiSetBind(oPC, nToken, "btn_id_item_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_id_item_tooltip", JsonString(" Identify or UnIdentify the target item.")); + // Row 2 + NuiSetBind(oPC, nToken, "btn_heal_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_heal_tooltip", JsonString(" Heal target creature to max hitpoints.")); + NuiSetBind(oPC, nToken, "btn_clear_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_clear_tooltip", JsonString(" Clears a creature's actions including combat.")); + NuiSetBind(oPC, nToken, "btn_kill_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_kill_tooltip", JsonString(" Kill target creature doing 10,000 magic damage.")); + NuiSetBind(oPC, nToken, "btn_remove_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_remove_tooltip", JsonString(" Remove selected object or the nearest object to ground selection.")); + // Row 3 + NuiSetBind(oPC, nToken, "btn_jump_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_jump_tooltip", JsonString(" Jump to target location.")); + NuiSetBind(oPC, nToken, "btn_kill_area_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_kill_area_tooltip", JsonString(" Kills all creatures in target area.")); +} +int StartingUp(object oPC) +{ + if(GetLocalInt(oPC, AI_ADD_PLUGIN)) + { + json jPlugin = JsonArray(); + jPlugin = JsonArrayInsert(jPlugin, JsonString("pi_test")); + jPlugin = JsonArrayInsert(jPlugin, JsonInt(FALSE)); + jPlugin = JsonArrayInsert(jPlugin, JsonString("Testing Menu")); + jPlugin = JsonArrayInsert(jPlugin, JsonString("ir_charsheet")); + json jPlugins = GetLocalJson(oPC, AI_JSON_PLUGINS); + jPlugins = JsonArrayInsert(jPlugins, jPlugin); + SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugin); + SetLocalInt(oPC, AI_PLUGIN_SET, TRUE); + return TRUE; + } + if(!GetLocalInt(oPC, AI_STARTING_UP)) return FALSE; + return TRUE; +} + diff --git a/src/module/nss/pinc_henchmen.nss b/src/module/nss/pinc_henchmen.nss new file mode 100644 index 0000000..a67141a --- /dev/null +++ b/src/module/nss/pinc_henchmen.nss @@ -0,0 +1,1531 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: pinc_henchmen +//////////////////////////////////////////////////////////////////////////////// + Include file for Henchmen plug in scripts for Philos Module Extentions. + +Database Info: +Slot 0 - henchname = the save slot 1 - 8. +Slots 1 - 8 define the selections: + henchname = Saved character selected. + image = Current character selected. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_nui" +#include "nw_inc_gff" + +const string HENCHMAN_DATABASE = "philos_henchman_db"; +const string HENCHMAN_TABLE = "HENCHMAN_TABLE"; +const string HENCHMAN_TO_EDIT = "HENCHMAN_TO_EDIT"; + +// Creates the table and initializes if it needs to. +void CheckHenchmanDataAndInitialize(object oPC, string sSlot); +// Removes a henchan from the current slot. +void RemoveHenchmanDb(object oPC, string sSlot); +// sDataField should be one of the data fields for that table. +// sData is the string data to be saved. +void SetHenchmanDbString(object oPC, string sDataField, string sData, string sSlot); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +string GetHenchmanDbString(object oPC, string sDataField, string sSlot); +// sDataField should be one of the data fields for that table. +// jData is the json data to be saved. +void SetHenchmanDbJson(object oPC, string sDataField, json jData, string sSlot); +// sDataField should be one of the data fields for the table. +// Returns a string of the data stored. +json GetHenchmanDbJson(object oPC, string sDataField, string sSlot); +// sSlot is the slot to define this object in the database for this Slot## (# Party button and #1-6). +// oHenchman is the PC/Henchman to be saved. +void SetHenchmanDbObject(object oPC, object oHenchman, string sSlot); +// sSlot is the slot to define this object in the database for this Slot## (# Party button and #1-6). +// lLocationToSpawn will spawn the object at that location. +object GetHenchmanDbObject(object oPC, location lLocationToSpawn, string sSlot); +// Returns TRUE if the henchman with sName can join. +int GetJoinButtonActive(object oPC, string sName); +// Returns a two letter alignment string. +string GetAlignText(object oHenchman); +// Populates the Saved character group. +void AddSavedCharacterInfo(object oPC, int nToken, string sParty); +// Populates the Current character group. +void AddCurrentCharacterInfo(object oPC, int nToken, string sParty); +// Removes a henchman from your party. +void RemoveYourHenchman(object oPC, int nToken, string sParty); +// Removes all henchman from the party. +void RemoveWholeParty(object oPC, int nToken, string sParty); +// Saves a henchman in your party to the saved party #. +void SaveYourHenchman(object oPC, int nToken, string sParty); +// Saves the whole party to the saved party #. +void SaveWholeParty(object oPC, int nToken, string sParty); +// Saves the players current party to party #. +void SavedPartyJoin(object oPC, int nToken, string sParty); +// Saves a character in the players party to party #. +void SavedCharacterJoin(object oPC, int nToken, string sParty); +// Clears the players saved party #. +void SavedPartyCleared(object oPC, int nToken, string sParty); +// Sets oHenchmans scripts to the current AI. +void SetHenchmanScripts(object oHenchman); +// If a henchman does not have a LvlStatList this will create one for them. +// nLevels allows the creation of x levels for LvlStatList using the 1st class. +// 0 on nLevels makes the function build it based on current levels. +json CreateLevelStatList(json jHenchman, object oHenchman, object oPC, int nLevels = 0); +// Resets the character to level one in the first class. +object ResetCharacter(object oPC, object oHenchman); +// Creates a menu to edit a characters information. +void CreateCharacterEditGUIPanel(object oPC, object oAssociate); +// Creates a character description menu. +void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, string sDescription); + +void CreateHenchmanDataTable () +{ + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, + "CREATE TABLE IF NOT EXISTS " + HENCHMAN_TABLE + " (" + + "name TEXT, " + + "slot TEXT, " + + "henchname TEXT, " + + "image TEXT, " + + "stats TEXT, " + + "classes TEXT, " + + "henchman TEXT, " + + "PRIMARY KEY(slot));"); + SqlStep (sql); +} +void CheckHenchmanDataAndInitialize(object oPC, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' AND name=@tableName;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@tableName", HENCHMAN_TABLE); + if(!SqlStep (sql)) CreateHenchmanDataTable(); + sQuery = "SELECT slot FROM " + HENCHMAN_TABLE + " Where name = @name AND slot = @slot;"; + sql = SqlPrepareQueryCampaign("philos_henchman_db", sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + if(!SqlStep(sql)) + { + sQuery = "INSERT INTO " + HENCHMAN_TABLE + "(name, slot, henchname, image, stats, classes " + + ", henchman) VALUES (@name, @slot, @henchname, @image, @stats, @classes, @henchman);"; + sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + SqlBindString(sql, "@henchname", ""); + SqlBindString(sql, "@image", ""); + SqlBindString(sql, "@stats", ""); + SqlBindString(sql, "@classes", ""); + SqlBindJson(sql, "@henchman", JsonObject()); + SqlStep(sql); + } +} +void RemoveHenchmanDb(object oPC, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "DELETE FROM " + HENCHMAN_TABLE + " WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + SqlStep(sql); +} +void SetHenchmanDbString(object oPC, string sDataField, string sData, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET " + sDataField + " = @data WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@data", sData); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + SqlStep(sql); +} +string GetHenchmanDbString(object oPC, string sDataField, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "SELECT " + sDataField + " FROM " + HENCHMAN_TABLE + " WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + if(SqlStep (sql)) return SqlGetString(sql, 0); + else return ""; +} +void SetHenchmanDbJson(object oPC, string sDataField, json jData, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET " + sDataField + + " = @data WHERE name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindJson (sql, "@data", jData); + SqlBindString(sql, "@name", sPCName); + SqlBindString (sql, "@slot", sSlot); + SqlStep (sql); +} +json GetHenchmanDbJson(object oPC, string sDataField, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "SELECT " + sDataField + " FROM " + HENCHMAN_TABLE + " WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString (sql, "@slot", sSlot); + if (SqlStep (sql)) return SqlGetJson (sql, 0); + else return JsonArray (); +} +void SetHenchmanDbObject(object oPC, object oHenchman, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET henchman = @henchman WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindObject(sql, "@henchman", oHenchman); + SqlBindString(sql, "@name", sPCName); + SqlBindString(sql, "@slot", sSlot); + SqlStep(sql); +} +object GetHenchmanDbObject(object oPC, location lLocationToSpawn, string sSlot) +{ + string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); + string sQuery = "SELECT henchman FROM " + HENCHMAN_TABLE + " WHERE " + + "name = @name AND slot = @slot;"; + sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); + SqlBindString(sql, "@name", sPCName); + SqlBindString (sql, "@slot", sSlot); + if (SqlStep (sql)) + { + json jHenchman = SqlGetJson(sql, 0); + string sTag = JsonGetString(GffGetString(jHenchman, "Tag")); + if(sTag == "") jHenchman = GffReplaceString(jHenchman, "Tag", "Hench_" + IntToString(Random(100))); + return JsonToObject(jHenchman, lLocationToSpawn, OBJECT_INVALID, TRUE); + } + return OBJECT_INVALID; +} +int GetJoinButtonActive(object oPC, string sName) +{ + if(sName == GetName(oPC)) return FALSE; + // Look for a free henchman slot, and if this henchman is already joined! + int nIndex = 1; + object oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(oHenchman != OBJECT_INVALID) + { + if(GetName(oHenchman) == sName) return FALSE; + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + return TRUE; +} +string GetAlignText(object oHenchman) +{ + string sAlign1, sAlign2; + switch (GetAlignmentLawChaos(oHenchman)) + { + case ALIGNMENT_LAWFUL : sAlign1 = "L"; break; + case ALIGNMENT_NEUTRAL : sAlign1 = "N"; break; + case ALIGNMENT_CHAOTIC : sAlign1 = "C"; break; + } + switch (GetAlignmentGoodEvil(oHenchman)) + { + case ALIGNMENT_GOOD : sAlign2 = "G"; break; + case ALIGNMENT_NEUTRAL : sAlign2 = "N"; break; + case ALIGNMENT_EVIL : sAlign2 = "E"; break; + } + string sAlign = sAlign1 + sAlign2; + if (sAlign == "NN") sAlign = "TN"; + return sAlign; +} +void AddSavedCharacterInfo(object oPC, int nToken, string sParty) +{ + string sHenchman = GetHenchmanDbString(oPC, "henchname", sParty); + // Add Henchman information. + if(sHenchman != "") + { + NuiSetBind (oPC, nToken, "btn_clear_party_event", JsonBool (TRUE)); + string sText = " Clears all characters from party " + sParty + "'s list!"; + NuiSetBind(oPC, nToken, "btn_clear_party_tooltip", JsonString(sText)); + NuiSetBind(oPC, nToken, "btn_join_party", JsonBool (TRUE)); + NuiSetBind(oPC, nToken, "btn_join_party_event", JsonBool (TRUE)); + sText = " Saved characters from party " + sParty + " enter the game and join you."; + NuiSetBind(oPC, nToken, "btn_join_party_tooltip", JsonString(sText)); + // Setup the henchman window. + string sName = GetHenchmanDbString(oPC, "henchname", sParty + sHenchman); + string sImage = GetHenchmanDbString(oPC, "image", sParty + sHenchman); + string sStats = GetHenchmanDbString(oPC, "stats", sParty + sHenchman); + string sClasses = GetHenchmanDbString(oPC, "classes", sParty + sHenchman); + NuiSetBind(oPC, nToken, "lbl_save_char_label", JsonString(sName)); + NuiSetBind(oPC, nToken, "img_saved_portrait_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "img_saved_portrait_image", JsonString(sImage + "l")); + NuiSetBind(oPC, nToken, "lbl_saved_stats_label", JsonString(sStats)); + NuiSetBind(oPC, nToken, "lbl_saved_classes_label", JsonString(sClasses)); + NuiSetBind(oPC, nToken, "btn_saved_join_label", JsonString("Join")); + NuiSetBind(oPC, nToken, "btn_saved_join_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_saved_remove_event", JsonBool(TRUE)); + //NuiSetBind(oPC, nToken, "btn_saved_edit_event", JsonBool(TRUE)); + } + else + { + NuiSetBind(oPC, nToken, "lbl_save_char_label", JsonString("Empty Party")); + NuiSetBind (oPC, nToken, "btn_clear_party_event", JsonBool (FALSE)); + NuiSetBind (oPC, nToken, "btn_join_party", JsonBool (FALSE)); + NuiSetBind (oPC, nToken, "btn_join_party_event", JsonBool (FALSE)); + // Setup the henchman window. + NuiSetBind(oPC, nToken, "img_saved_portrait_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "img_saved_portrait_image", JsonString("po_hu_m_99_l")); + NuiSetBind(oPC, nToken, "lbl_saved_stats_label", JsonString("")); + NuiSetBind(oPC, nToken, "lbl_saved_classes_label", JsonString("")); + NuiSetBind(oPC, nToken, "btn_saved_join_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_saved_join_label", JsonString("Join")); + NuiSetBind(oPC, nToken, "btn_saved_remove_event", JsonBool(FALSE)); + NuiSetBind(oPC, nToken, "btn_saved_edit_event", JsonBool(FALSE)); + } +} +void AddCurrentCharacterInfo(object oPC, int nToken, string sParty) +{ + string sHenchman = GetHenchmanDbString(oPC, "image", sParty); + if(sHenchman == "") + { + CheckHenchmanDataAndInitialize(oPC, sParty); + SetHenchmanDbString(oPC, "image", "0", sParty); + } + int nHenchman = StringToInt(sHenchman); + int nIndex = 0; + object oCharacter; + while(nIndex < AI_MAX_HENCHMAN) + { + if(nIndex == 0) oCharacter = oPC; + else oCharacter = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oCharacter == OBJECT_INVALID) + { + nIndex = 0; + oCharacter = oPC; + break; + } + else if(nHenchman == nIndex) break; + nIndex++; + } + // Adjust the party buttons. + int bParty = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1) != OBJECT_INVALID; + //NuiSetBind(oPC, nToken, "btn_save_party", JsonBool (bParty)); + NuiSetBind(oPC, nToken, "btn_save_party_event", JsonBool (bParty)); + //NuiSetBind(oPC, nToken, "btn_remove_party", JsonBool (bParty)); + NuiSetBind(oPC, nToken, "btn_remove_party_event", JsonBool (bParty)); + if(bParty) + { + string sText = " Saves all henchman from your current party to party " + sParty + "."; + NuiSetBind(oPC, nToken, "btn_save_party_tooltip", JsonString(sText)); + sText = " Removes all henchman from your current party!"; + NuiSetBind(oPC, nToken, "btn_remove_party_tooltip", JsonString(sText)); + } + // Setup the henchman window. + string sName = GetName(oCharacter); + string sImage = GetPortraitResRef(oCharacter); + string sStats = GetAlignText(oCharacter) + " "; + if(GetGender(oCharacter) == GENDER_MALE) sStats += "Male "; + else sStats += "Female "; + int nPosition = 1; + sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oCharacter)))); + string sClasses = GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oCharacter)))); + sClasses += " " + IntToString (GetLevelByPosition (nPosition, oCharacter)); + int nClass = GetClassByPosition(++nPosition, oCharacter); + while(nClass != CLASS_TYPE_INVALID) + { + sClasses += ", " + GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", nClass))); + sClasses += " " + IntToString (GetLevelByPosition (nPosition, oCharacter)); + nClass = GetClassByPosition(++nPosition, oCharacter); + } + NuiSetBind(oPC, nToken, "lbl_game_char_label", JsonString(sName)); + NuiSetBind(oPC, nToken, "img_cur_portrait_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "img_cur_portrait_image", JsonString(sImage + "l")); + NuiSetBind(oPC, nToken, "lbl_cur_stats_label", JsonString(sStats)); + NuiSetBind(oPC, nToken, "lbl_cur_classes_label", JsonString(sClasses)); + NuiSetBind(oPC, nToken, "btn_cur_save_label", JsonString("Save")); + NuiSetBind(oPC, nToken, "btn_cur_save_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cur_edit_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_cur_remove_event", JsonBool(TRUE)); +} +object GetSelectedHenchman(object oPC, string sParty) +{ + string sHenchman = GetHenchmanDbString(oPC, "image", sParty); + if(sHenchman == "") + { + CheckHenchmanDataAndInitialize(oPC, sParty); + SetHenchmanDbString(oPC, "image", "0", sParty); + } + int nHenchman = StringToInt(sHenchman); + int nIndex = 0; + object oCharacter; + while(nIndex < AI_MAX_HENCHMAN) + { + if(nIndex == 0) oCharacter = oPC; + else oCharacter = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oCharacter == OBJECT_INVALID) + { + nIndex = 0; + oCharacter = oPC; + break; + } + else if(nHenchman == nIndex) break; + nIndex++; + } + return oCharacter; +} +void RemoveYourHenchman(object oPC, int nToken, string sParty) +{ + object oHenchman = GetSelectedHenchman(oPC, sParty); + if(oHenchman == oPC) ai_SendMessages("You cannot remove the player from the party!", AI_COLOR_RED, oPC); + else + { + RemoveHenchman(oPC, oHenchman); + AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); + NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oHenchman) + AI_WIDGET_NUI)); + DestroyObject(oHenchman); + } + ai_SendMessages(GetName(oHenchman) + " has been removed from the party!", AI_COLOR_GREEN, oPC); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +void RemoveWholeParty(object oPC, int nToken, string sParty) +{ + int nIndex = AI_MAX_HENCHMAN; + object oHenchman; + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(nIndex > 0) + { + if(oHenchman != OBJECT_INVALID) + { + ai_SendMessages(GetName(oHenchman) + " has been remove from your Party.", AI_COLOR_YELLOW, oPC); + RemoveHenchman(oPC, oHenchman); + AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); + NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oHenchman) + AI_WIDGET_NUI)); + DestroyObject(oHenchman); + } + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, --nIndex); + } + ai_SendMessages("All of your henchman have been remove from the Party.", AI_COLOR_YELLOW, oPC); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +void SaveYourHenchman(object oPC, int nToken, string sParty) +{ + int bPC, nIndex, nClass, nPosition, nMaxHenchman = AI_MAX_HENCHMAN + 1; + string sName, sIndex, sSlot, sStats, sClasses; + object oHenchman = GetSelectedHenchman(oPC, sParty); + if(oHenchman == oPC) + { + bPC = TRUE; + oHenchman = CopyObject(oPC, GetLocation(oPC), OBJECT_INVALID, "hench_" + IntToString(Random(100)), TRUE); + SetHenchmanScripts(oHenchman); + } + string sHenchmanName = GetName(oHenchman); + while(nIndex < nMaxHenchman) + { + sIndex = IntToString(nIndex); + sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); + if(sName == sHenchmanName || sName == "") + { + sSlot = sParty + sIndex; + if(!bPC) RemoveHenchman(oPC, oHenchman); + // Special check for Infinite Dungeon plot givers to be changed into henchman. + if(GetStringLeft(GetLocalString(oHenchman, "sConversation"), 8) == "id1_plot") + { + DeleteLocalString(oHenchman, "sConversation"); + } + ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER); + json jHenchman = ObjectToJson(oHenchman, TRUE); + if(!bPC) AddHenchman(oPC, oHenchman); + else DestroyObject(oHenchman); + //string sPatch = "[{\"op\":\"replace\",\"path\":\"/FactionID/value\",\"value\":1}]"; + //json jPatch = JsonParse(sPatch); + //jHenchman = JsonPatch(jHenchman, jPatch); + CheckHenchmanDataAndInitialize(oPC, sSlot); + SetHenchmanDbString(oPC, "image", GetPortraitResRef(oHenchman), sSlot); + SetHenchmanDbString(oPC, "henchname", sHenchmanName, sSlot); + sStats = GetAlignText(oHenchman) + " "; + if(GetGender(oHenchman) == GENDER_MALE) sStats += "Male "; + else sStats += "Female "; + nPosition = 1; + sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oHenchman)))); + sClasses = GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oHenchman)))); + sClasses += " " + IntToString (GetLevelByPosition (nPosition, oHenchman)); + nClass = GetClassByPosition(++nPosition, oHenchman); + while(nClass != CLASS_TYPE_INVALID) + { + sClasses += ", " + GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oHenchman)))); + sClasses += " " + IntToString (GetLevelByPosition (nPosition, oHenchman)); + nClass = GetClassByPosition(++nPosition, oHenchman); + } + SetHenchmanDbString(oPC, "stats", sStats, sSlot); + SetHenchmanDbString(oPC, "classes", sClasses, sSlot); + SetHenchmanDbJson(oPC, "henchman", jHenchman, sSlot); + if(sName == "") ai_SendMessages(sHenchmanName + " has been saved to the party.", AI_COLOR_GREEN, oPC); + else ai_SendMessages(sHenchmanName + " has replaced a copy of themselves in the party.", AI_COLOR_GREEN, oPC); + break; + } + nIndex++; + } +if(nIndex == nMaxHenchman) ai_SendMessages("This party is full!", AI_COLOR_RED, oPC); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +void SaveWholeParty(object oPC, int nToken, string sParty) +{ + int nIndex = AI_MAX_HENCHMAN; + object oHenchman; + while(nIndex > 0) + { + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + if(oHenchman != OBJECT_INVALID) + { + SetHenchmanDbString(oPC, "image", IntToString(nIndex), sParty); + SaveYourHenchman(oPC, nToken, sParty); + } + nIndex--; + } + ai_SendMessages("All of your henchman have been saved to Party " + sParty + ".", AI_COLOR_YELLOW, oPC); + SetHenchmanDbString(oPC, "henchname", "0", sParty); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +void SavedPartyJoin(object oPC, int nToken, string sParty) +{ + int bFound, nIndex, nDBHenchman = 0; + json jHenchman; + object oHenchman, oLoadedHenchman; + string sDBHenchman = IntToString(nDBHenchman); + string sName = GetHenchmanDbString(oPC, "henchname", sParty + sDBHenchman); + while(sName != "") + { + bFound = FALSE; + nIndex = 1; + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(oHenchman != OBJECT_INVALID) + { + if(sName == GetName(oPC) || GetName(oHenchman) == sName) + { + bFound = TRUE; + break; + } + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + if(!bFound) + { + ai_SendMessages(sName + " has joined your party.", AI_COLOR_GREEN, oPC); + jHenchman = GetHenchmanDbJson(oPC, "henchman", sParty + sDBHenchman); + oLoadedHenchman = JsonToObject(jHenchman, GetLocation(oPC), OBJECT_INVALID, TRUE); + AddHenchman(oPC, oLoadedHenchman); + } + else ai_SendMessages(sName + " is already in your party!", AI_COLOR_RED, oPC); + sDBHenchman = IntToString(++nDBHenchman); + sName = GetHenchmanDbString(oPC, "henchname", sParty + sDBHenchman); + } + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +void SavedCharacterJoin(object oPC, int nToken, string sParty) +{ + int nIndex, bFound; + object oHenchman, oLoadedHenchman; + string sHenchman = GetHenchmanDbString(oPC, "henchname", sParty); + string sName = GetHenchmanDbString(oPC, "henchname", sParty + sHenchman); + nIndex = 1; + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); + while(oHenchman != OBJECT_INVALID) + { + if(sName == GetName(oPC) || GetName(oHenchman) == sName) + { + bFound = TRUE; + break; + } + oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); + } + if(!bFound) + { + ai_SendMessages(sName + " has joined your party!", AI_COLOR_GREEN, oPC); + oLoadedHenchman = GetHenchmanDbObject(oPC, GetLocation(oPC), sParty + sHenchman); + AddHenchman(oPC, oLoadedHenchman); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); + } + else ai_SendMessages(sName + " is already in your party!", AI_COLOR_RED, oPC); +} +void SavedPartyCleared(object oPC, int nToken, string sParty) +{ + int nIndex, nMaxHenchman = AI_MAX_HENCHMAN + 1; + object oHenchman, oLoadedHenchman; + string sIndex = IntToString(nIndex); + string sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); + while(nIndex < nMaxHenchman) + { + if(sName != "") + { + RemoveHenchmanDb(oPC, sParty + sIndex); + ai_SendMessages(sName + " has been cleared from the saved party " + sParty + ".", AI_COLOR_YELLOW, oPC); + } + sIndex = IntToString(++nIndex); + sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); + } + SetHenchmanDbString(oPC, "henchname", "", sParty); + NuiDestroy(oPC, nToken); + ExecuteScript("pi_henchmen", oPC); +} +json CreateOptionsAlignment(object oHenchman, int nAlignType) +{ + json jAlignNameList = JsonArray(); + if(nAlignType == 0) + { + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Lawful")); + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Neutral")); + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Chaotic")); + } + else + { + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Good")); + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Neutral")); + jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Evil")); + } + return jAlignNameList; +} +json CreateOptionsClasses(object oHenchman) +{ + int nIndex = 1, nClass; + string sClassName; + json jClassNameList = JsonArray(); + while(nIndex < 5) + { + nClass = GetClassByPosition(nIndex, oHenchman); + if(nClass == CLASS_TYPE_INVALID) sClassName = "Empty"; + else + { + sClassName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + sClassName += " " + IntToString(GetLevelByClass(nClass, oHenchman)); + } + jClassNameList = JsonArrayInsert(jClassNameList, JsonString(sClassName)); + nIndex++; + } + return jClassNameList; +} +json jArrayInsertClasses() +{ + int nIndex, nClass, nMaxClass = Get2DARowCount("classes"); + string sClassName; + json jClassNameCombo = JsonArray(); + while(nIndex < nMaxClass) + { + if(Get2DAString("classes", "PlayerClass", nIndex) == "1") + { + sClassName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nIndex))); + jClassNameCombo = JsonArrayInsert(jClassNameCombo, NuiComboEntry(sClassName, nClass)); + nClass++; + } + nIndex++; + } + return jClassNameCombo; +} +int GetSelectionByClass2DA(int nClass) +{ + int nIndex, nSelection, nMaxClass = Get2DARowCount("classes"); + while(nIndex < nMaxClass) + { + if(Get2DAString("classes", "PlayerClass", nIndex) == "1") + { + if(nClass == nIndex) return nSelection; + nSelection++; + } + nIndex++; + } + return -1; +} +int GetClassBySelection2DA(int nSelection) +{ + int nIndex, nClass, nMaxClass = Get2DARowCount("classes"); + while(nClass < nMaxClass) + { + if(Get2DAString("classes", "PlayerClass", nClass) == "1") + { + if(nSelection == nIndex) return nClass; + nIndex++; + } + nClass++; + } + return -1; +} +json ArrayInsertPackages(string sClass) +{ + int nIndex, nPackage, nMaxPackage = Get2DARowCount("packages"); + string sPackageName; + json jPackageNameCombo = JsonArray(); + while(nIndex < nMaxPackage) + { + if(Get2DAString("packages", "ClassID", nIndex) == sClass) + { + sPackageName = Get2DAString("packages", "Label", nIndex); + //GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nIndex))); + if(sPackageName != "Bad Strref" && sPackageName != "") + { + jPackageNameCombo = JsonArrayInsert(jPackageNameCombo, NuiComboEntry(sPackageName, nPackage)); + nPackage++; + } + } + nIndex++; + } + return jPackageNameCombo; +} +int GetSelectionByPackage2DA(string sClass, int nPackage) +{ + int nIndex, nSelection, nMaxPackage = Get2DARowCount("packages"); + string sPackageName; + while(nIndex < nMaxPackage) + { + if(Get2DAString("packages", "ClassID", nIndex) == sClass) + { + sPackageName = GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nIndex))); + if(sPackageName != "Bad Strref" && sPackageName != "") + { + if(nPackage == nIndex) return nSelection; + nSelection++; + } + } + nIndex++; + } + return -1; +} +int GetPackageBySelection2DA(string sClass, int nSelection) +{ + int nIndex, nPackage, nMaxPackage = Get2DARowCount("packages"); + while(nPackage < nMaxPackage) + { + if(Get2DAString("packages", "ClassID", nPackage) == sClass) + { + if(nSelection == nIndex) return nPackage; + nIndex++; + } + nPackage++; + } + return -1; +} +json ArrayInsertSoundSets(object oHenchman) +{ + int nIndex, nSoundSet, nSoundSetType, nMaxSets = Get2DARowCount("soundset"); + string sGender = IntToString(GetGender(oHenchman)); + string sSoundSetName, sResRef; + json jSoundSetNameCombo = JsonArray(); + while(nIndex < nMaxSets) + { + if(Get2DAString("soundset", "GENDER", nIndex) == sGender) + { + nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nIndex)); + if(nSoundSetType < 5) + { + sSoundSetName = GetStringByStrRef(StringToInt(Get2DAString("soundset", "STRREF", nIndex))); + sResRef = GetStringLowerCase(Get2DAString("soundset", "RESREF", nIndex)); + if(GetStringLeft(sResRef, 4) == "vs_f") sSoundSetName += " (Full)"; + else if(GetStringLeft(sResRef, 4) == "vs_n") sSoundSetName += " (Part)"; + jSoundSetNameCombo = JsonArrayInsert(jSoundSetNameCombo, NuiComboEntry(sSoundSetName, nSoundSet)); + nSoundSet++; + } + } + nIndex++; + } + return jSoundSetNameCombo; +} +int GetSelectionBySoundSet2DA(object oHenchman, int nSoundSet) +{ + int nIndex, nSelection, nSoundSetType, nMaxSoundSet = Get2DARowCount("soundset"); + string sGender = IntToString(GetGender(oHenchman)); + while(nIndex < nMaxSoundSet) + { + if(Get2DAString("soundset", "GENDER", nIndex) == sGender) + { + nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nIndex)); + if(nSoundSetType < 5) + { + if(nSoundSet == nIndex) return nSelection; + nSelection++; + } + } + nIndex++; + } + return -1; +} +int GetSoundSetBySelection2DA(object oHenchman, int nSelection) +{ + int nIndex, nSoundSet, nSoundSetType, nMaxSoundSet = Get2DARowCount("soundset"); + string sGender = IntToString(GetGender(oHenchman)); + while(nSoundSet < nMaxSoundSet) + { + if(Get2DAString("soundset", "GENDER", nSoundSet) == sGender) + { + nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nSoundSet)); + if(nSoundSetType < 5) + { + if(nSelection == nIndex) return nSoundSet; + nIndex++; + } + } + nSoundSet++; + } + return -1; +} +void SetHenchmanScripts(object oHenchman) +{ + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_ch_ac1"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_ch_ac2"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_ch_ac3"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "nw_ch_ac4"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "nw_ch_ac5"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "nw_ch_ac6"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DEATH, "nw_ch_ac7"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "nw_ch_ac8"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "nw_ch_ac9"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_RESTED, "nw_ch_aca"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "nw_ch_acb"); + SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "nw_ch_ace"); +} +object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion) +{ + jHenchman = GffReplaceResRef(jHenchman, "ScriptSpawn", ""); + object oHenchman = JsonToObject(jHenchman, lLocation, OBJECT_INVALID, TRUE); + AddHenchman(oPC, oHenchman); + DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE"); + string sAssociateType = ai_GetAssociateType(oPC, oHenchman); + NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)); + if(nFamiliar) SummonFamiliar(oHenchman); + if(nCompanion) SummonAnimalCompanion(oHenchman); + return oHenchman; +} +json CreateLevelStatList(json jHenchman, object oHenchman, object oPC, int nLevels = 0) +{ + int nClass = GetClassByPosition(1, oHenchman); + int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClass)); + SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); + json jSkill = JsonObject(); + jSkill = GffAddByte(jSkill, "Rank", 0); + jSkill = JsonObjectSet(jSkill, "__struct_id", JsonInt(0)); + json jSkillArray = JsonArray(); + int nNumOfSkills; + for(nNumOfSkills = Get2DARowCount("skills"); nNumOfSkills > 0; nNumOfSkills--) + { + jSkillArray = JsonArrayInsert(jSkillArray, jSkill); + } + json jLevel = JsonObject(); + jLevel = GffAddByte(jLevel, "EpicLevel", 0); + jLevel = GffAddList(jLevel, "FeatList", JsonArray()); + jLevel = GffAddByte(jLevel, "LvlStatClass", nClass); + jLevel = GffAddByte(jLevel, "LvlStatHitDie", nHitDie); + jLevel = GffAddList(jLevel, "SkillList", jSkillArray); + jLevel = GffAddWord(jLevel, "SkillPoints", 0); + jLevel = JsonObjectSet(jLevel, "__struct_id", JsonInt(0)); + json jLevelArray = JsonArray(); + if(nLevels == 0) nLevels = GetLevelByPosition(1, oHenchman); + for(nLevels; nLevels > 0; nLevels--) + { + jLevelArray = JsonArrayInsert(jLevelArray, jLevel); + } + WriteTimestampedLogEntry("pinc_henchmen, 813, Adding LvlStatList to " + GetName(oHenchman)); + return GffAddList(jHenchman, "LvlStatList", jLevelArray); +} +int CanSelectFeat(json jCreature, object oCreature, int nFeat, int nPosition = 1) +{ + // Check if all classes can use. + int n2DAStat = StringToInt(Get2DAString("feat", "ALLCLASSESCANUSE", nFeat)); + if(n2DAStat == 0) + { + int bPass, nClassFeat, nRow, nClass = GetClassByPosition(nPosition, oCreature); + string sClsFeat2DAName = Get2DAString("classes", "FeatsTable", nClass); + int nMaxRow = Get2DARowCount(sClsFeat2DAName); + while(nRow < nMaxRow) + { + nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nRow)); + if(nClassFeat == nFeat) + { + bPass = TRUE; + break; + } + nRow++; + } + if(!bPass) return FALSE; + } + n2DAStat = StringToInt(Get2DAString("feat", "MINATTACKBONUS", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "BaseAttackBonus")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINSTR", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Str")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINDEX", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Dex")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINCON", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Con")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MININT", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Int")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINWIS", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Wis")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINCHA", nFeat)); + if(JsonGetInt(GffGetByte(jCreature, "Cha")) < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "MINSPELLLVL", nFeat)); + int nSpellLevel = 0, nClass = GetClassByPosition(nPosition, oCreature); + string s2DAName = Get2DAString("classes", "SpellGainTable", nClass); + int nLevel = GetLevelByPosition(nPosition, oCreature); + if(s2DAName != "") + { + nSpellLevel = StringToInt(Get2DAString(s2DAName, "NumSpellLevels", nLevel - 1)) - 1; + } + if(nSpellLevel < n2DAStat) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "PREREQFEAT1", nFeat)); + if(n2DAStat > 0) + { + // ************************************** Add code to search jCreature's feats! + if(!GetHasFeat(n2DAStat, oCreature)) return FALSE; + n2DAStat = StringToInt(Get2DAString("feat", "PREREQFEAT2", nFeat)); + if(!GetHasFeat(n2DAStat, oCreature)) return FALSE; + } + int nIndex; + while(nIndex < 5) + { + n2DAStat = StringToInt(Get2DAString("feat", "OrReqFeat" + IntToString(nIndex), nFeat)); + if(nIndex == 0 && n2DAStat == 0) break; + if(GetHasFeat(n2DAStat, oCreature)) break; + nIndex++; + if(nIndex == 5) return FALSE; + } + string s2DAStat = Get2DAString("feat", "REQSKILL", nFeat); + if(s2DAStat != "") + { + n2DAStat = StringToInt(s2DAStat); + int bCanUse; + if(Get2DAString("skills", "AllClassesCanUse", n2DAStat) == "1") bCanUse = TRUE; + else + { + string sClsSkill2DA = Get2DAString("classes", "SkillsTable", nClass); + int bPass, nClassSkill, nRow, nMaxRow = Get2DARowCount(sClsSkill2DA); + while(nRow < nMaxRow) + { + nClassSkill = StringToInt(Get2DAString(sClsSkill2DA, "SkillIndex", nRow)); + if(nClassSkill == n2DAStat) + { + bCanUse = TRUE; + break; + } + nRow++; + } + } + if(bCanUse) + { + int nSkillReq = StringToInt(Get2DAString("feat", "ReqSkillMinRanks", n2DAStat)); + // ************************** Add code to check jCreatures skills. + if(GetSkillRank(n2DAStat, oCreature, TRUE) < nSkillReq) return FALSE; + } + else return FALSE; + } + s2DAStat = Get2DAString("feat", "REQSKILL2", nFeat); + if(s2DAStat != "") + { + n2DAStat = StringToInt(s2DAStat); + int bCanUse; + if(Get2DAString("skills", "AllClassesCanUse", n2DAStat) == "1") bCanUse = TRUE; + else + { + string sClsSkill2DA = Get2DAString("classes", "SkillsTable", nClass); + int bPass, nClassSkill, nRow, nMaxRow = Get2DARowCount(sClsSkill2DA); + while(nRow < nMaxRow) + { + nClassSkill = StringToInt(Get2DAString(sClsSkill2DA, "SkillIndex", nRow)); + if(nClassSkill == n2DAStat) + { + bCanUse = TRUE; + break; + } + nRow++; + } + } + if(bCanUse) + { + int nSkillReq = StringToInt(Get2DAString("feat", "ReqSkillMinRanks2", n2DAStat)); + if(GetSkillRank(n2DAStat, oCreature, TRUE) < nSkillReq) return FALSE; + } + else return FALSE; + } + n2DAStat = StringToInt(Get2DAString("feat", "MinLevel", nFeat)); + if(n2DAStat > 0) + { + int bPass, nClassPosition, nPositionClass, nPositionLevel; + int nClassRequired = StringToInt(Get2DAString("feat", "MinLevelClass", nFeat)); + while(nClassPosition < AI_MAX_CLASSES_PER_CHARACTER) + { + // ***************************** Rework to check jCreature class list instead. + nPositionClass = GetClassByPosition(nClassPosition, oCreature); + if(nPositionClass == nClassRequired) + { + nPositionLevel = GetLevelByPosition(nClassPosition, oCreature); + if(nPositionLevel < n2DAStat) return FALSE; + else bPass = TRUE; + } + nClassPosition++; + } + if(!bPass) return FALSE; + } + n2DAStat = StringToInt(Get2DAString("feat", "MinFortSave", nFeat)); + if(JsonGetInt(GffGetChar(jCreature, "FortSaveThrow")) < n2DAStat) return FALSE; + s2DAStat = Get2DAString("feat", "PreReqEpic", nFeat); + if(s2DAStat == "1") return FALSE; + return TRUE; +} +json ResetFeats(json jHenchman, object oHenchman) +{ + int nLevel = 0; + // We remake the Feat list if the character doesn't have a level list! + json jFeatList = JsonArray(); + json jFeat; + int nRace = GetRacialType(oHenchman); + string sRace2DAName = Get2DAString("racialtypes", "FeatsTable", nRace); + // Give racial feats. + int nRaceRow, nRaceFeat; + int nRaceMaxRow = Get2DARowCount(sRace2DAName); + while(nRaceRow < nRaceMaxRow) + { + nRaceFeat = StringToInt(Get2DAString(sRace2DAName, "FeatIndex", nRaceRow)); + jFeat = JsonObject(); + jFeat = GffAddWord(jFeat, "Feat", nRaceFeat); + jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); + jFeatList = JsonArrayInsert(jFeatList, jFeat); + WriteTimestampedLogEntry("pinc_henchmen, 973, Adding racial feat: " + + Get2DAString("feat", "LABEL", nRaceFeat)); + nRaceRow++; + } + // Give class feats. + int nClass = GetClassByPosition(1, oHenchman); + string sGranted, sList; + string sClsFeat2DAName = Get2DAString("classes", "FeatsTable", nClass); + int nClassRow, nClassFeat, nClassMaxRow = Get2DARowCount(sClsFeat2DAName); + while(nClassRow < nClassMaxRow) + { + sGranted = Get2DAString(sClsFeat2DAName, "GrantedOnLevel", nClassRow); + if(sGranted == "1") + { + sList = Get2DAString(sClsFeat2DAName, "List", nClassRow); + if(sList == "3") + { + nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nClassRow)); + jFeat = JsonObject(); + jFeat = GffAddWord(jFeat, "Feat", nClassFeat); + jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); + jFeatList = JsonArrayInsert(jFeatList, jFeat); + WriteTimestampedLogEntry("pinc_henchmen, 995, Adding class feat: " + + Get2DAString("feat", "LABEL", nClassFeat)); + } + } + nClassRow++; + } + // Give any bonus feats from package. + int nPackageFeat, nPackageRow; + string sBonusFeat2DAName = Get2DAString("classes", "BonusFeatsTable", nClass); + int nNumOfFeats = StringToInt(Get2DAString(sBonusFeat2DAName, "Bonus", nLevel)); + string sPackage2DAName = Get2DAString("packages", "FeatPref2DA", nClass); + int nPackageMaxRow = Get2DARowCount(sPackage2DAName); + // Give bonus feats based on the package. + nPackageRow = 0; + if(nNumOfFeats > 0) + { + while(nPackageRow < nPackageMaxRow) + { + nPackageFeat = StringToInt(Get2DAString(sPackage2DAName, "FeatIndex", nPackageRow)); + nClassRow = 0; + while(nClassRow < nClassMaxRow) + { + nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nClassRow)); + if(nClassFeat == nPackageFeat) + { + sList = Get2DAString(sClsFeat2DAName, "List", nClassRow); + if((sList == "1" || sList == "2") && CanSelectFeat(jHenchman, oHenchman, nClassFeat)) + { + jFeat = JsonObject(); + jFeat = GffAddWord(jFeat, "Feat", nClassFeat); + jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); + jFeatList = JsonArrayInsert(jFeatList, jFeat); + WriteTimestampedLogEntry("pinc_henchmen, 1028, Adding class bonus feat: " + + Get2DAString("feat", "LABEL", nPackageFeat)); + nNumOfFeats--; + } + } + nClassRow++; + } + if(nNumOfFeats < 1) break; + nPackageRow++; + } + } + // Give picked feats from package. + nNumOfFeats = 1; + if(GetHasFeat(FEAT_QUICK_TO_MASTER, oHenchman)) nNumOfFeats++; + nPackageRow = 0; + while(nPackageRow < nPackageMaxRow) + { + nClassRow = 0; + nPackageFeat = StringToInt(Get2DAString(sPackage2DAName, "FeatIndex", nPackageRow)); + if(CanSelectFeat(jHenchman, oHenchman, nPackageFeat)) + { + jFeat = JsonObject(); + jFeat = GffAddWord(jFeat, "Feat", nPackageFeat); + jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); + jFeatList = JsonArrayInsert(jFeatList, jFeat); + WriteTimestampedLogEntry("pinc_henchmen, 1053, Adding character bonus feat: " + + Get2DAString("feat", "LABEL", nPackageFeat)); + nNumOfFeats--; + } + if(nNumOfFeats < 1) break; + nPackageRow++; + } + jHenchman = GffReplaceList(jHenchman, "FeatList", jFeatList); + return jHenchman; +} +json ResetSkills(json jHenchman, object oHenchman) +{ + // We remake the Skill List if the character doesn't have a level list! + int nClass = GetClassByPosition(1, oHenchman); + int nSkillPoints, nIntMod = GetAbilityModifier(ABILITY_INTELLIGENCE, oHenchman); + if(nIntMod > 0) nSkillPoints = nIntMod * 4; + if(GetRacialType(oHenchman) == RACIAL_TYPE_HUMAN) nSkillPoints += 4; + nSkillPoints += StringToInt(Get2DAString("classes", "SkillPointBase", nClass)) * 4; + int nMaxRanks = 5; + json jSkillList = JsonArray(); + json jSkill; + // Setup the Skill List. + int nIndex, nSkillMaxRow = Get2DARowCount("skills"); + for(nIndex = 0; nIndex < nSkillMaxRow; nIndex++) + { + jSkill = JsonObject(); + jSkill = GffAddByte(jSkill, "Rank", 0); + jSkill = JsonObjectSet(jSkill, "__struct_id", JsonInt(0)); + jSkillList = JsonArrayInsert(jSkillList, jSkill); + } + // Give skill points based on the package. + int nPackageSkill, nPackageRow, nCurrentRanks, bCrossClass, nClassRow, nNewRanks; + string sPackage2DAName = Get2DAString("packages", "SkillPref2DA", nClass); + int nPackageMaxRow = Get2DARowCount(sPackage2DAName); + string sClass2DAName = Get2DAString("classes", "SkillsTable", nClass); + int nClassMaxRow = Get2DARowCount(sClass2DAName); + nPackageRow = 0; + while(nPackageRow < nPackageMaxRow && nSkillPoints > 0) + { + nPackageSkill = StringToInt(Get2DAString(sPackage2DAName, "SkillIndex", nPackageRow)); + jSkill = JsonArrayGet(jSkillList, nPackageSkill); + nCurrentRanks = JsonGetInt(GffGetByte(jSkill, "Rank")); + nClassRow = 0; + while(nClassRow < nClassMaxRow) + { + if(nPackageSkill == StringToInt(Get2DAString(sClass2DAName, "SkillIndex", nClassRow))) + { + bCrossClass = Get2DAString(sClass2DAName, "ClassSkill", nClassRow) == "0"; + break; + } + nClassRow++; + } + if(bCrossClass) nNewRanks = (nMaxRanks / 2) - nCurrentRanks; + else nNewRanks = nMaxRanks - nCurrentRanks; + if(nNewRanks > nSkillPoints) nNewRanks = nSkillPoints; + if(nNewRanks > 0) + { + jSkill = GffReplaceByte(jSkill, "Rank", nCurrentRanks + nNewRanks); + jSkillList = JsonArraySet(jSkillList, nPackageSkill, jSkill); + WriteTimestampedLogEntry("pinc_henchmen, 1110, Adding " + IntToString(nNewRanks) + + " ranks to " + Get2DAString("skills", "Label", nPackageSkill)); + nSkillPoints -= nNewRanks; + } + nPackageRow++; + } + jHenchman = GffReplaceList(jHenchman, "SkillList", jSkillList); + return jHenchman; +} +json ResetSpellsKnown(json jClass, object oHenchman) +{ + int nClass = GetClassByPosition(1, oHenchman); + if(Get2DAString("classes", "SpellCaster", nClass) == "0") return jClass; + int nLevel = 0; + // We remake the Known spell list if the character doesn't have a level list! + json jKnownList, jMemorizedList; + json jSpell, jSpellsPerDayList; + int bMemorizesSpells = StringToInt(Get2DAString("classes", "MemorizesSpells", nClass)); + int bSpellBookRestricted = StringToInt(Get2DAString("classes", "SpellBookRestricted", nClass)); + string sSpellKnown2DAName = Get2DAString("classes", "SpellKnownTable", nClass); + string sSpellGained2DAName = Get2DAString("classes", "SpellGainTable", nClass); + string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass); + string sSpellPackage2DAName = Get2DAString("packages", "SpellPref2DA", nClass); + int nPackageSpell, nPackageRow; + int nPackageMaxRow = Get2DARowCount(sSpellPackage2DAName); + int nKnownSpellIndex, nSpellsKnown, nAbility, nSpellLevel = 0; + string sKnownListName, sSpellLevel, sPackageSpellLevel, sAbility; + // Cycle through all spell levels and reset. + while(nSpellLevel < 10) + { + sSpellLevel = IntToString(nSpellLevel); + WriteTimestampedLogEntry("pinc_henchmen, 1143, Checking Spell Level: " + sSpellLevel); + // Recreate the 0th and 1st level based on the package. + if(nSpellLevel < 2 && bSpellBookRestricted) + { + // Spellbook restricted that don't have a SpellsKnown2DAName + // get to keep all 0th level spells so we skip them. Example:Wizard + if(nSpellLevel != 0 || sSpellKnown2DAName != "") + { + // Classes that are spell book restricted but don't have a SpellKnownTable + // get 3 spells + Ability Modifier worth of spells like a wizard. + if(sSpellKnown2DAName == "") + { + sAbility = Get2DAString("classes", "SpellCastingAbil", nClass); + if(sAbility == "INT") nAbility = ABILITY_INTELLIGENCE; + else if(sAbility == "WIS") nAbility = ABILITY_WISDOM; + else if(sAbility == "CHA") nAbility = ABILITY_CHARISMA; + nSpellsKnown = 3 + GetAbilityModifier(nAbility, oHenchman); + } + else + { + nSpellsKnown = StringToInt(Get2DAString(sSpellKnown2DAName, "SpellLevel" + sSpellLevel, nLevel)); + } + WriteTimestampedLogEntry("pinc_henchmen, 1165, nSpellsKnown: " + IntToString(nSpellsKnown)); + jKnownList = JsonArray(); + nPackageRow = 0; + while(nPackageRow < nPackageMaxRow && nSpellsKnown > 0) + { + nPackageSpell = StringToInt(Get2DAString(sSpellPackage2DAName, "SpellIndex", nPackageRow)); + sPackageSpellLevel = Get2DAString("spells", sSpellTableColumn, nPackageSpell); + if(sPackageSpellLevel == sSpellLevel) + { + jSpell = JsonObject(); + jSpell = GffAddWord(jSpell, "Spell", nPackageSpell); + jSpell = JsonObjectSet(jSpell, "__struct_id", JsonInt(3)); + jKnownList = JsonArrayInsert(jKnownList, jSpell); + WriteTimestampedLogEntry("pinc_henchmen, 1178, Adding known spell: " + + Get2DAString("spells", "LABEL", nPackageSpell)); + nSpellsKnown--; + } + nPackageRow++; + } + if(JsonGetLength(jKnownList) == 0) + { + jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel); + WriteTimestampedLogEntry("pinc_henchmen, 1187, Removing KnownList" + sSpellLevel); + } + else if(JsonGetType(GffGetList(jClass, "KnownList" + sSpellLevel)) != JSON_TYPE_NULL) + { + jClass = GffReplaceList(jClass, "KnownList" + sSpellLevel, jKnownList); + } + else jClass = GffAddList(jClass, "KnownList" + sSpellLevel, jKnownList); + } + } + // Remove all other known spell levels and memorized levels. + else + { + jKnownList = GffGetList(jClass, "KnownList" + sSpellLevel); + if(JsonGetType(jKnownList) != JSON_TYPE_NULL) + { + jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel); + WriteTimestampedLogEntry("pinc_henchmen, 1203, Removing KnownList" + sSpellLevel); + } + } + if(bMemorizesSpells) + { + jMemorizedList = GffGetList(jClass, "MemorizedList" + sSpellLevel); + if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL) + { + jClass = GffRemoveList(jClass, "MemorizedList" + sSpellLevel); + WriteTimestampedLogEntry("pinc_henchmen, 1210, Removing MemorizedList" + sSpellLevel); + } + } + else + { + jSpellsPerDayList = GffGetList(jClass, "SpellsPerDayList"); + nSpellsKnown = StringToInt(Get2DAString(sSpellGained2DAName, "SpellLevel"+ sSpellLevel, nLevel)); + jSpell = JsonArrayGet(jSpellsPerDayList, nSpellLevel); + jSpell = GffReplaceByte(jSpell, "NumSpellsLeft", nSpellsKnown); + jSpellsPerDayList = JsonArraySet(jSpellsPerDayList, nSpellLevel, jSpell); + jClass = GffReplaceList(jClass, "SpellsPerDayList", jSpellsPerDayList); + WriteTimestampedLogEntry("pinc_henchmen, 1223, Setting SpellsPerDay to " + + IntToString(nSpellsKnown)); + } + nSpellLevel++; + } + return jClass; +} +object ResetCharacter(object oPC, object oHenchman) +{ + SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); + RemoveHenchman(oPC, oHenchman); + json jHenchman = ObjectToJson(oHenchman, TRUE); + json jClassList = GffGetList(jHenchman, "ClassList"); + json jClass = JsonArrayGet(jClassList, 0); + // Set the Class list to the first class only and put at level 1. + int nClass = JsonGetInt(JsonObjectGet(jClass, "Class")); + jClass = GffReplaceShort(jClass, "ClassLevel", 1); + // Delete extra classes. + int nClassIndex = JsonGetLength(jClassList) - 1; + while(nClassIndex > 0) + { + jClassList = JsonArrayDel(jClassList, nClassIndex--); + } + int nHitPoints = StringToInt(Get2DAString("classes", "HitDie", nClass)); + int nMod = JsonGetInt(GffGetByte(jHenchman, "Con")); + if(nMod > 9) nHitPoints += (nMod - 10) / 2; + else nHitPoints += (nMod - 11) / 2; + jHenchman = GffReplaceShort(jHenchman, "CurrentHitPoints", nHitPoints); + jHenchman = GffReplaceShort(jHenchman, "HitPoints", nHitPoints); + jHenchman = GffReplaceShort(jHenchman, "MaxHitPoints", nHitPoints); + jHenchman = GffReplaceDword(jHenchman, "Experience", 0); + jHenchman = GffReplaceFloat(jHenchman, "ChallengeRating", 1.0); + string s2DA = Get2DAString("classes", "AttackBonusTable", nClass); + int nAtk = StringToInt(Get2DAString(s2DA, "BAB", 0)); + jHenchman = GffReplaceByte(jHenchman, "BaseAttackBonus", nAtk); + s2DA = Get2DAString("classes", "SavingThrowTable", nClass); + int nSave = StringToInt(Get2DAString(s2DA, "FortSave", 0)); + jHenchman = GffReplaceChar(jHenchman, "FortSaveThrow", nSave); + nSave = StringToInt(Get2DAString(s2DA, "RefSave", 0)); + jHenchman = GffReplaceChar(jHenchman, "RefSaveThrow", nSave); + nSave = StringToInt(Get2DAString(s2DA, "WillSave", 0)); + jHenchman = GffReplaceChar(jHenchman, "WillSaveThrow", nSave); + json jLvlStatList = GffGetList(jHenchman, "LvlStatList"); + if(JsonGetType(jLvlStatList) != JSON_TYPE_NULL) + { + WriteTimestampedLogEntry("pinc_henchmen 1275, jLvlStatList: " + JsonDump(jLvlStatList, 4)); + int nLevel = 1, nLevelTrack = 1; + int nAbilityStatIncrease, nAbility; + string sAbility; + json jAbility; + json jLevel = JsonArrayGet(jLvlStatList, nLevel); + while(JsonGetType(jLevel) != JSON_TYPE_NULL) + { + WriteTimestampedLogEntry("inc_henchmen, 1297, Checking level " + IntToString(nLevelTrack)); + // Remove all Ability score increases for each level from ability scores. + jAbility = GffGetByte(jLevel, "LvlStatAbility"); + if(JsonGetType(jAbility) != JSON_TYPE_NULL) + { + nAbilityStatIncrease = JsonGetInt(jAbility); + if(nAbilityStatIncrease == ABILITY_STRENGTH) sAbility = "Str"; + if(nAbilityStatIncrease == ABILITY_DEXTERITY) sAbility = "Dex"; + if(nAbilityStatIncrease == ABILITY_CONSTITUTION) sAbility = "Con"; + if(nAbilityStatIncrease == ABILITY_INTELLIGENCE) sAbility = "Int"; + if(nAbilityStatIncrease == ABILITY_WISDOM) sAbility = "Wis"; + if(nAbilityStatIncrease == ABILITY_CHARISMA) sAbility = "Cha"; + nAbility = JsonGetInt(GffGetByte(jHenchman, sAbility)) - 1; + jHenchman = GffReplaceByte(jHenchman, sAbility, nAbility); + WriteTimestampedLogEntry("pinc_henchmen, 1314, Removing " + sAbility + " level bonus ability score point."); + } + jLvlStatList = JsonArrayDel(jLvlStatList, nLevel); + // Note: nLevel is not incremented since we are removing the previous level. + // there for when we get the same level again its the next level! + jLevel = JsonArrayGet(jLvlStatList, nLevel); + //SendMessageToPC(oPC, "jLvlStatList: " + JsonDump(jLvlStatList, 4)); + nLevelTrack++; + } + jHenchman = GffRemoveList(jHenchman, "LvlStatList"); + } + jHenchman = CreateLevelStatList(jHenchman, oHenchman, oPC, 1); + jHenchman = ResetSkills(jHenchman, oHenchman); + jHenchman = ResetFeats(jHenchman, oHenchman); + jClass = ResetSpellsKnown(jClass, oHenchman); + jClassList = JsonArraySet(jClassList, 0, jClass); + jHenchman = GffReplaceList(jHenchman, "ClassList", jClassList); + //WriteTimestampedLogEntry("pinc_henchmen 1397, jHenchman: " + JsonDump(jHenchman, 4)); + location lLocation = GetLocation(oHenchman); + int nFamiliar, nCompanion; + object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHenchman); + if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; + oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHenchman); + if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; + AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); + DestroyObject(oHenchman); + oHenchman = ai_AddHenchman(oPC, jHenchman, lLocation, nFamiliar, nCompanion); + return oHenchman; +} +// ********* New Henchman windows ********** +void CreateCharacterEditGUIPanel(object oPC, object oHenchman) +{ + // Set window to not save until it has been created. + SetLocalInt(oPC, "0_No_Win_Save", TRUE); + DelayCommand(0.5f, DeleteLocalInt (oPC, "0_No_Win_Save")); + // Group 1 (Portrait)******************************************************* 151 / 73 + // Group 1 Row 1 *********************************************************** 350 / 91 + json jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateTextEditBox (jGroupRow, "name_placeholder", "char_name", 15, FALSE, 140.0, 20.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add the group row to the group column. + json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + // Group 1 Row 1 *********************************************************** 350 / 91 + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateTextEditBox (jGroupRow, "port_placeholder", "port_name", 15, FALSE, 140.0, 20.0, "port_tooltip"); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add the group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 1 Row 2 *********************************************************** 350 / 259 + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateImage(jGroupRow, "", "port_resref", NUI_ASPECT_EXACTSCALED, NUI_HALIGN_CENTER, NUI_VALIGN_TOP, 140.0f, 160.0f); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add the group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 1 Row 3 *********************************************************** 350 / 292 + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateButton (jGroupRow, "<", "btn_portrait_prev", 42.0f, 25.0f); + jGroupRow = CreateButton (jGroupRow, "Set", "btn_portrait_ok", 44.0f, 25.0f); + jGroupRow = CreateButton (jGroupRow, ">", "btn_portrait_next", 42.0f, 25.0f); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 1 Row 4 *********************************************************** 350 / 91 + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateLabel(jGroupRow, "Sound Set", "lbl_sound_set", 140.0, 10.0f, NUI_HALIGN_CENTER, NUI_VALIGN_BOTTOM); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add the group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 1 Row 5 *********************************************************** 350 / 325 + jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jGroupRow = CreateCombo(jGroupRow, ArrayInsertSoundSets(oHenchman), "cmb_soundset", 140.0, 25.0); + jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + json jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); + // Group 2 (Stats)********************************************************** 151 / 73 + // Group 2 Row 1 *********************************************************** 350 / 91 + jGroupRow = CreateLabel(JsonArray(), "", "lbl_stats", 150.0, 15.0, 0, NUI_VALIGN_BOTTOM, 0.0); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); + + // Group 2 Row 2 *********************************************************** 350 / 243 + //json jAlign = CreateOptionsAlignment(oHenchman, 0); + //jGroupRow = CreateOptions(JsonArray(), "opt_lawchaos", NUI_DIRECTION_HORIZONTAL, jAlign, 60.0, 35.0); + // Add group row to the group column. + //jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 3 *********************************************************** 350 / 243 + //jAlign = CreateOptionsAlignment(oHenchman, 1); + //jGroupRow = CreateOptions(JsonArray(), "opt_goodevil", NUI_DIRECTION_HORIZONTAL, jAlign, 60.0, 35.0); + //jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); + // Add group row to the group column. + //jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 2 *********************************************************** 350 / 243 + json jClasses = CreateOptionsClasses(oHenchman); + jGroupRow = CreateOptions(JsonArray(), "opt_classes", NUI_DIRECTION_VERTICAL, jClasses, 150.0, 144.0); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 3 *********************************************************** 350 / 276 + jGroupRow = CreateButton(JsonArray(), "Level Up", "btn_level_up", 150.0f, 25.0f, -1.0, "btn_level_up_tooltip"); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 4 *********************************************************** 350 / 309 + jGroupRow = CreateButton (JsonArray(), "Reset Character", "btn_reset", 150.0f, 25.0f, -1.0, "btn_reset_tooltip"); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 5 *********************************************************** 350 / 342 + jGroupRow = CreateCombo(JsonArray(), jArrayInsertClasses(), "cmb_class", 150.0, 25.0); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + // Group 2 Row 6 *********************************************************** 350 / 375 + int nClassOption = GetLocalInt(oHenchman, "CLASS_OPTION_POSITION"); + int nClass = GetClassByPosition(nClassOption + 1, oHenchman); + int bNoClass = FALSE; + if(nClass == CLASS_TYPE_INVALID) + { + nClass = GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nClassOption + 1)); + bNoClass = TRUE; + } + string sClass = IntToString(nClass); + jGroupRow = CreateCombo(JsonArray(), ArrayInsertPackages(sClass), "cmb_package", 150.0, 25.0); + // Add group row to the group column. + jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); + jRow = JsonArrayInsert(jRow, NuiGroup(NuiCol(jGroupCol))); + // Add the row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 5 (text edit box)**************************************************** 350 / 518 + jRow = CreateTextEditBox(JsonArray(), "desc_placeholder", "desc_value", 1000, TRUE, 350.0, 150.0, "desc_tooltip"); + // Add the row to the column. + jCol = JsonArrayInsert(jCol, NuiRow (jRow)); + // Row 6 (button)*********************************************************** 350/ 546 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton (jRow, "Save Description", "btn_desc_save", 150.0f, 20.0f); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow (jRow)); + // Set the Layout of the window. + json jLayout = NuiCol (jCol); + // Get the window location to restore it from the database. + CheckHenchmanDataAndInitialize(oPC, "0"); + json jData = GetHenchmanDbJson(oPC, "henchman", "0"); + json jGeometry = JsonObjectGet(jData, "henchman_edit_nui"); + float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); + float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); + if(fX == 0.0 && fY == 0.0) + { + fX = -1.0; + fY = -1.0; + } + string sName = GetName(oHenchman); + if(GetStringRight(sName, 1) == "s") sName = sName + "'"; + else sName = sName + "'s"; + int nToken = SetWindow (oPC, jLayout, "henchman_edit_nui", sName + " Character editor", + fX, fY, 380.0, 588.0, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_henchmen"); + // Set all binds, events, and watches. + int nID = GetPortraitId (oPC); + NuiSetUserData(oPC, nToken, JsonInt(nID)); + string sResRef = GetPortraitResRef(oHenchman); + NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); + NuiSetBind(oPC, nToken, "char_name", JsonString(GetName(oHenchman))); + NuiSetBindWatch(oPC, nToken, "char_name", TRUE); + NuiSetBind(oPC, nToken, "char_name_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "port_name", JsonString(sResRef)); + NuiSetBindWatch(oPC, nToken, "port_name", TRUE); + NuiSetBind(oPC, nToken, "port_name_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "port_resref_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "port_resref_image", JsonString(sResRef + "l")); + NuiSetBind(oPC, nToken, "port_tooltip", JsonString (" You may also type the portrait file name.")); + // Set buttons active. + NuiSetBind(oPC, nToken, "btn_portrait_prev_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_portrait_next_event", JsonBool(TRUE)); + int nSelection = GetSelectionBySoundSet2DA(oHenchman, GetSoundset(oHenchman)); + NuiSetBind(oPC, nToken, "cmb_soundset_selected", JsonInt(nSelection)); + NuiSetBindWatch(oPC, nToken, "cmb_soundset_selected", TRUE); + NuiSetBind(oPC, nToken, "cmb_soundset_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_desc_save_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_portrait_ok_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "desc_tooltip", JsonString(" You can use color codes!")); + string sDescription = GetDescription(oHenchman); + NuiSetBind(oPC, nToken, "desc_value_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "desc_value", JsonString (sDescription)); + // Setup the henchman window. + string sStats = GetAlignText(oHenchman) + " "; + if(GetGender(oHenchman) == GENDER_MALE) sStats += "Male "; + else sStats += "Female "; + sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oHenchman)))); + NuiSetBind(oPC, nToken, "lbl_stats_label", JsonString(sStats)); + json jHenchman = ObjectToJson(oHenchman); + NuiSetBind(oPC, nToken, "opt_classes_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "opt_classes_value", JsonInt(nClassOption)); + NuiSetBind(oPC, nToken, "btn_level_up_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_level_up_tooltip", JsonString(" Levels the character up by one level in selected class.")); + if(ai_GetIsCharacter(oHenchman)) NuiSetBind(oPC, nToken, "btn_reset_event", JsonBool(FALSE)); + else NuiSetBind(oPC, nToken, "btn_reset_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_reset_tooltip", JsonString(" Resets the character to level 1.")); + nSelection = GetSelectionByClass2DA(nClass); + NuiSetBind(oPC, nToken, "cmb_class_selected", JsonInt(nSelection)); + NuiSetBindWatch(oPC, nToken, "cmb_class_selected", bNoClass); + NuiSetBind(oPC, nToken, "cmb_class_event", JsonBool(bNoClass)); + int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1)); + if(nPackage == 0) + { + nPackage = GetPackageBySelection2DA(sClass, 0); + SetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1), nPackage); + } + NuiSetBind(oPC, nToken, "cmb_package_selected", JsonInt(GetSelectionByPackage2DA(sClass, nPackage))); + NuiSetBindWatch(oPC, nToken, "cmb_package_selected", bNoClass); + NuiSetBind(oPC, nToken, "cmb_package_event", JsonBool(bNoClass)); +} +void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, string sDescription) +{ + // Row 1 ******************************************************************* 500 / 469 + json jRow = CreateImage(JsonArray(), "", "char_icon", NUI_ASPECT_FIT, NUI_HALIGN_CENTER, NUI_VALIGN_MIDDLE, 40.0, 40.0); + jRow = CreateTextBox(jRow, "char_text", 380.0, 400.0); + // Add row to the column. + json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); + // Row 2 ******************************************************************* 500 / 522 + jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); + jRow = CreateButton(jRow, "OK", "btn_ok", 150.0f, 45.0f); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Set the Layout of the window. + json jLayout = NuiCol(jCol); + int nToken = SetWindow(oPC, jLayout, "char_description_nui", sName, + -1.0, -1.0, 460.0f, 537.0 + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_henchmen"); + json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oPC))); + NuiSetUserData(oPC, nToken, jData); + // Row 1 + NuiSetBind(oPC, nToken, "char_icon_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "char_icon_image", JsonString(sIcon)); + NuiSetBind(oPC, nToken, "char_text_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "char_text", JsonString(sDescription)); + // Row 2 + NuiSetBind(oPC, nToken, "btn_ok_event", JsonBool(TRUE)); +} + diff --git a/src/module/nss/xx_pc_1_hb.nss b/src/module/nss/xx_pc_1_hb.nss new file mode 100644 index 0000000..7dac876 --- /dev/null +++ b/src/module/nss/xx_pc_1_hb.nss @@ -0,0 +1,79 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_1_hb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnHeart beat script for PC AI; + This will usually fire every 6 seconds (1 game round). +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_menus" +void ai_ActionFollow(object oCreature, object oTarget) +{ + if(GetLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE) == AI_LAST_ACTION_MOVE) + { + float fDistance = GetDistanceBetween(oCreature, oTarget); + float fFollowDistance = ai_GetFollowDistance(oCreature); + if(fDistance > fFollowDistance && !ai_GetIsInCombat(oCreature)) + { + if(fDistance > fFollowDistance * 5.0) AssignCommand(oCreature, JumpToObject(oTarget)); + else + { + ClearAllActions(); + ActionMoveToObject(oTarget, TRUE, fFollowDistance); + } + } + DelayCommand(1.0, ai_ActionFollow(oCreature, oTarget)); + } +} +void main() +{ + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("xx_pc_1_hb", "12", GetName(oCreature) + " heartbeat."); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound(oCreature); + return; + } + if(ai_CheckForCombat(oCreature, FALSE)) return; + if(IsInConversation(oCreature)) return; + if(ai_TryHealing(oCreature, oCreature)) return; + if(ai_CheckNearbyObjects(oCreature)) return; + if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) + { + if(AI_DEBUG) ai_Debug("xx_ch_1_hb", "47", "Going into stealth mode!"); + int nStealth = GetSkillRank(SKILL_HIDE, oCreature); + nStealth += GetSkillRank(SKILL_MOVE_SILENTLY, oCreature); + if(nStealth / 2 >= ai_GetCharacterLevels(oCreature)) + { + SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); + SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + } + } + else + { + SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); + if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH)) + { + if(AI_DEBUG) ai_Debug("xx_ch_1_hb", "61", "Going into search mode!"); + SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); + } + else SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); + } + // Finally we check to make sure we are following. + if(GetCurrentAction(oCreature) != ACTION_FOLLOW) + { + // Follow associate. + object oAssociate = GetLocalObject(oCreature, AI_FOLLOW_TARGET); + if(oAssociate == OBJECT_INVALID || GetMaster(oAssociate) != oCreature) return; + if(GetDistanceBetween(oCreature, oAssociate) > ai_GetFollowDistance(oCreature)) + { + ai_ClearCreatureActions(); + if(AI_DEBUG) ai_Debug("XX_pc_1_hb", "75", "Follow master: " + + " Stealth: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) + + " Search: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH))); + SetLocalInt(oCreature, AI_CURRENT_ACTION_MODE, AI_LAST_ACTION_MOVE); + ai_ActionFollow(oCreature, oAssociate); + //ActionMoveToObject(oAssociate, TRUE, ai_GetFollowDistance(oCreature)); + } + } +} diff --git a/src/module/nss/xx_pc_2_percept.nss b/src/module/nss/xx_pc_2_percept.nss new file mode 100644 index 0000000..9731f70 --- /dev/null +++ b/src/module/nss/xx_pc_2_percept.nss @@ -0,0 +1,107 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_2_percept + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnPerception script for PC AI; + There are 4 types of perception - Heard, Inaudible, Seen, Vanished. + Only one type will ever be true in an event trigger. + The order of trigger is Heard/Seen and Inaudible/Vanished. + There are two states of percepion Heard and Seen. + These states can be set at the same time thus a heard event can see the creature. + Fires when ever one of these states changes from TRUE to FALSE or FALSE to TRUE. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oLastPerceived = GetLastPerceived(); + if(AI_DEBUG) + { + if(GetLastPerceptionHeard ()) + { + ai_Debug("xx_pc_2_percept", "22", GetName(oCreature) + " heard " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + + " Seen: " + IntToString(GetObjectSeen(oLastPerceived, oCreature)) + "."); + } + if(GetLastPerceptionSeen ()) + { + ai_Debug("xx_pc_2_percept", "29", GetName(oCreature) + " sees " + + GetName(GetLastPerceived()) + " Distance: " + + FloatToString(GetDistanceBetween(GetLastPerceived(), oCreature), 0, 2) + "."); + } + if(GetLastPerceptionVanished ()) + { + ai_Debug("xx_pc_2_percept", "35", GetName(oCreature) + " lost sight of " + + GetName(GetLastPerceived()) + "."); + } + } + // We do nothing on Inaudibles so drop out early! + if(GetLastPerceptionInaudible()) + { + ai_Debug("xx_pc_2_percept", "42", GetName(oCreature) + " lost sound of " + + GetName(GetLastPerceived()) + "."); + return; + } + if(AI_DEBUG) ai_Debug("xx_pc_2_percept", "46", "Dead? " + IntToString(GetIsDead(oLastPerceived)) + + " Enemy? " + IntToString(GetIsEnemy(oLastPerceived, oCreature))); + if(ai_Disabled(oCreature)) return; + if(GetIsDead(oLastPerceived) || !GetIsEnemy(oLastPerceived, oCreature)) return; + // All code below assumes the perceived creature is an enemy and is alive! + // **************************** ENEMY HEARD ******************************** + if(GetLastPerceptionHeard()) + { + // Since Heard is run before Seen, but the values are set at the same + // time we can skip heard checks on heard & seen creatures! + if(GetObjectSeen(oLastPerceived, oCreature)) + { + // If the creature we are perceiving was our invisible creature then + // remove that they are invisible. + if(oLastPerceived == GetLocalObject(oCreature, AI_IS_INVISIBLE)) + { + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); + } + ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_SEE_AN_ENEMY); + } + else ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_HEARD_AN_ENEMY); + return; + } + // **************************** ENEMY SEEN ********************************* + if(GetLastPerceptionSeen()) + { + // If the creature we are perceiving was our invisible creature then + // remove that they are invisible. + if(oLastPerceived == GetLocalObject(oCreature, AI_IS_INVISIBLE)) + { + DeleteLocalObject(oCreature, AI_IS_INVISIBLE); + } + ai_AssociateEvaluateNewThreat(oCreature, oLastPerceived, AI_I_SEE_AN_ENEMY); + return; + } + // **************************** ENEMY VANISHED ***************************** + if(GetLastPerceptionVanished()) + { + // Lets keep a mental note of the invisible creature. + SetLocalObject(oCreature, AI_IS_INVISIBLE, oLastPerceived); + if(AI_DEBUG) ai_Debug("xx_pc_2_percept", "86", " We saw " + GetName(oLastPerceived) + " disappear!"); + if(ai_GetIsBusy(oCreature)) return; + // If in combat check to see if our target disappeared. + // If they have and we are not in melee with them then reevaluate combat + // since we lost our target. + if(ai_GetIsInCombat(oCreature)) + { + if(AI_DEBUG) ai_Debug("xx_pc_2_percept", "93", "Is this our target? " + + IntToString(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived)); + if(ai_GetAttackedTarget(oCreature, TRUE, TRUE) == oLastPerceived) + { + ai_DoAssociateCombatRound(oCreature); + } + return; + } + // If they are not invisible then that means they left our perception + // range and we need follow them. + ActionMoveToObject(oLastPerceived, TRUE, AI_RANGE_CLOSE); + } + // **************************** ENEMY INAUDIBLE***************************** + // Not used. +} diff --git a/src/module/nss/xx_pc_3_endround.nss b/src/module/nss/xx_pc_3_endround.nss new file mode 100644 index 0000000..51126e6 --- /dev/null +++ b/src/module/nss/xx_pc_3_endround.nss @@ -0,0 +1,60 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_3_endround + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnCombatRoundEnd event script for PC AI; + Fires at the end of each combat round (6 seconds). + This will fire as long as oCreature is in combat (GetIsInCombat()). + This event starts counting once a combat action is started. + Every time a spell is cast it will queue another end combat round so haste with + two spells cast will fire this twice in one round. + It will also fire at the end of a hostile effect that stops actions i.e Stunned, Knockdown etc. + Action modes are also cleared prior to this event executing! + GetAttemptedAttackTarget() & GetAttemptedSpellTarget() also get cleared prior to this event. + This event can be canceled with ClearAllActions(TRUE) and SurrenderToEnemies. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + if(AI_DEBUG) ai_Debug("xx_pc_3_endround", "20", GetName(oCreature) + " ends combat round."); + if(ai_Disabled(oCreature)) return; + // Action modes get cleared prior to each OnCombatRoundEnd! + // We do this to keep the action mode going. + int nActionMode = GetLocalInt(oCreature, AI_CURRENT_ACTION_MODE); + if(nActionMode > 0) + { + SetActionMode(oCreature, nActionMode, TRUE); + // We don't want to use up all of the Dwarven Defenders uses! + if(nActionMode == 12) IncrementRemainingFeatUses(oCreature, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE); + } + int nAction = GetCurrentAction(oCreature); + if(AI_DEBUG) ai_Debug("xx_pc_3_endround", "32", "nAction: " + IntToString(nAction)); + switch(nAction) + { + // These actions are uninteruptable. + case ACTION_MOVETOPOINT : + case ACTION_CASTSPELL : + case ACTION_ITEMCASTSPELL : + case ACTION_COUNTERSPELL : return; + // Might be doing a special action that is not a defined action. + case ACTION_INVALID : + { + int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + if(AI_DEBUG) ai_Debug("xx_pc_3_endround", "47", "nCombatWait: " + IntToString(nCombatWait)); + if(nCombatWait) + { + if(ai_IsInCombatRound(oCreature, nCombatWait)) return; + DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS); + } + break; + } + // We always want to interupt an attack action at the end of a round (6 seconds). + case ACTION_ATTACKOBJECT : + { + if(ai_IsInCombatRound(oCreature, AI_COMBAT_ROUND_IN_SECONDS)) return; + } + } + if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound (oCreature); +} + diff --git a/src/module/nss/xx_pc_4_convers.nss b/src/module/nss/xx_pc_4_convers.nss new file mode 100644 index 0000000..413aef1 --- /dev/null +++ b/src/module/nss/xx_pc_4_convers.nss @@ -0,0 +1,30 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_4_convers + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnDialoge event script for PC AI; + Fires when oCreature has been clicked on for conversation. + Fires when oCreature hears a shout from another creature. + If SetListening is FALSE then oCreature will not "hear" anything. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + int nMatch = GetListenPatternNumber(); + object oLastSpeaker = GetLastSpeaker(); + if(AI_DEBUG) ai_Debug("xx_pc_4_convers", "17", GetName(oCreature) + " listens " + + IntToString(nMatch) + " to " + GetName(oLastSpeaker) + "." + + " Searching: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING))); + // If we are disabled then we can't listen or talk, Busy is checked in ai_SelectAssociateCommand(). + // Some modules disable the player then talk to them! So it should be ok + // to keep this remarked out. + // Some commands override being busy so we check in ai_SelectAssociateCommand. + if(nMatch != -1) + { + if(!GetFactionEqual(oLastSpeaker, oCreature)) return; + if(!ai_Disabled(oCreature)) ai_SelectAssociateCommand(oCreature, oLastSpeaker, nMatch); + } + else BeginConversation("", oLastSpeaker); +} + diff --git a/src/module/nss/xx_pc_5_phyatked.nss b/src/module/nss/xx_pc_5_phyatked.nss new file mode 100644 index 0000000..1c6ba79 --- /dev/null +++ b/src/module/nss/xx_pc_5_phyatked.nss @@ -0,0 +1,29 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_5_phyatked + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnPhysicalAttacked event script for PC AI; + Fires for all physical attacks, claws, weapons, fists, bow, etc. + Fires for taunt skill, animal empathy skill. +/*////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oAttacker = GetLastAttacker(); + if(AI_DEBUG) ai_Debug("xx_pc_5_phyatked", "14", GetName(oCreature) + " was attacked by " + + GetName(oAttacker) + "."); + SetLocalObject(oAttacker, AI_ATTACKED_PHYSICAL, oCreature); + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; + if(ai_GetIsInCombat(oCreature)) return; + // We only inform others if attacked when not busy, not disabled, & not in combat. + SetLocalObject(oCreature, AI_MY_TARGET, oAttacker); + SpeakString(AI_ATKED_BY_WEAPON, TALKVOLUME_SILENT_TALK); + // The only way to get here is to not be in combat thus we have not + // perceived them so lets look for them. + if(!ai_CanIAttack(oCreature)) return; + if(GetDistanceBetween(oCreature, oAttacker) < AI_RANGE_CLOSE) ai_DoAssociateCombatRound(oCreature); + else ActionMoveToObject(oAttacker, TRUE, AI_RANGE_CLOSE - 1.0); +} + + diff --git a/src/module/nss/xx_pc_6_damaged.nss b/src/module/nss/xx_pc_6_damaged.nss new file mode 100644 index 0000000..c3d6aaa --- /dev/null +++ b/src/module/nss/xx_pc_6_damaged.nss @@ -0,0 +1,27 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_6_damaged + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Associate (Summons, Familiars, Companions) OnDamaged script; + Does not fire if the creature dies from the damage. + Does not fire for plot creatures as they take no damage. + May fire before or after OnPhysicalAttacked event. + Fires when EffectDamage is applied to oCreature even if 0 damage. + Fires when a weapon damages a oCreature, but not if resisted. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + if(ai_Disabled(oCreature)) return; + // Make sure to clear wounded shout limit if we take damage. See ai_TryHealing. + DeleteLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT"); + object oDamager = GetLastDamager(oCreature); + if(AI_DEBUG) ai_Debug("xx_pc_6_damaged", "18", GetName(oCreature) + " has been damaged by " + GetName(oDamager)); + if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature) || ai_GetIsInCombat(oCreature)) return; + if(GetDistanceBetween(oCreature, oDamager) < AI_RANGE_CLOSE) ai_DoAssociateCombatRound(oCreature); + else ActionMoveToObject(oDamager, TRUE, AI_RANGE_CLOSE - 1.0); +} + diff --git a/src/module/nss/xx_pc_8_disturb.nss b/src/module/nss/xx_pc_8_disturb.nss new file mode 100644 index 0000000..6440c03 --- /dev/null +++ b/src/module/nss/xx_pc_8_disturb.nss @@ -0,0 +1,21 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_8_disturb + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnDisturbed event script for PC AI. + Fires when the inventory of oCreature is changed i.e. added or removed. + Creatures can't have items added or removed from its inventory (it's not a + container), then the only way this fires for creatures if something is stolen. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + if(AI_DEBUG) ai_Debug("xx_pc_8_disturb", "14", GetName(OBJECT_SELF) + " is been disturbed!"); + // We do nothing at the moment... lets not mess up our factions ok? + // This should be defined by the server admins and is commented out. + //if(ai_GetIsBusy(OBJECT_SELF, FALSE) || ai_Disabled()) return; + //object oTarget = GetLastDisturbed(); + //if (oTarget != OBJECT_INVALID) ai_DoMonsterCombatRound (); +} + + diff --git a/src/module/nss/xx_pc_b_castat.nss b/src/module/nss/xx_pc_b_castat.nss new file mode 100644 index 0000000..5d4b85f --- /dev/null +++ b/src/module/nss/xx_pc_b_castat.nss @@ -0,0 +1,35 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_b_castat + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnSpellCastAt event script for PC AI; + Fires when oCreature becomes the target of a spell via SignalEvent. + Fires when a healing kit is used on a creature. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + object oCaster = GetLastSpellCaster(); + SetLocalObject(oCaster, AI_ATTACKED_SPELL, oCreature); + if(ai_Disabled(oCreature)) return; + if(!GetLastSpellHarmful()) return; + // If the spell came from an ally, we don't want to hold it against them. + if(GetFactionEqual(oCaster, oCreature)) ClearPersonalReputation(oCaster, oCreature); + // Lets see what kind of area of effect this is and select an appropriate action. + int nSpell = GetLastSpell(); + if(AI_DEBUG) ai_Debug("xx_pc_b_castat", "21", GetName(OBJECT_SELF) + " has been hit by a harmful spell(" + + Get2DAString("spells", "Label", nSpell) + ")!"); + if(ai_GetInAOEReaction(oCreature, oCaster, nSpell) && + ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return; + if(ai_GetIsBusy(oCreature)) return; + if(ai_CheckForCombat(oCreature, FALSE)) return; + // We were attacked by an enemy out of combat, so let our allies know. + SetLocalObject(oCreature, AI_MY_TARGET, oCaster); + SpeakString(AI_ATKED_BY_SPELL, TALKVOLUME_SILENT_TALK); + if(!ai_CanIAttack(oCreature)) return; + if(GetDistanceBetween(oCreature, oCaster) < AI_RANGE_CLOSE) ai_DoAssociateCombatRound(oCreature); + else ActionMoveToObject(oCaster, TRUE, AI_RANGE_CLOSE - 1.0); +} + + diff --git a/src/module/nss/xx_pc_e_blocked.nss b/src/module/nss/xx_pc_e_blocked.nss new file mode 100644 index 0000000..604513e --- /dev/null +++ b/src/module/nss/xx_pc_e_blocked.nss @@ -0,0 +1,68 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: xx_pc_e_blocked + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Player OnBlocked event script for PC AI; + Can be blocked by a creature or door. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + // This actually gets either a Creature or Door that is blocking OBJECT_SELF. + object oObject = GetBlockingDoor(); + if(AI_DEBUG) ai_Debug("xx_pc_e_blocked", "14", GetName(oCreature) + " is being blocked by " + GetName(oObject)); + int nObjectType = GetObjectType(oObject); + if(nObjectType == OBJECT_TYPE_CREATURE) + { + if(GetIsEnemy(oObject, oCreature)) + { + if(ai_CanIAttack(oCreature) && ai_GetIsInCombat(oCreature)) + { + ai_DoAssociateCombatRound(oCreature); + return; + } + if(ai_CheckForCombat(oCreature, FALSE)) return; + } + } + // Anything below blocking us is a door. + if(nObjectType != OBJECT_TYPE_DOOR) return; + //if(GetLockKeyTag(oObject) != "") return; + else if(GetIsDoorActionPossible(oObject, DOOR_ACTION_OPEN) && + GetAbilityScore(oCreature, ABILITY_INTELLIGENCE) >= 5) + { + DoDoorAction(oObject, DOOR_ACTION_OPEN); + return; + } + // Anything below is ignored in combat. + if(ai_GetIsInCombat(oCreature)) return; + // If we are in combat we should ignore doors that do not easily open. + if(GetIsDoorActionPossible(oObject, DOOR_ACTION_BASH) && + ai_GetWeaponDamage(oCreature, 3, TRUE) > GetHardness(oObject) && + GetLockKeyTag(oObject) == "") + { + ActionWait(1.0); + ActionAttack(oObject); + // Give them 3 rounds to break through a door. + DelayCommand(18.0, ai_ClearCreatureActions(TRUE)); + return; + } + else if(GetLocked(oObject)) + { + if(AI_DEBUG) ai_Debug("0e_ch_e_blocked", "49", GetName(oObject) + " is locked!"); + string sID = ObjectToString(oCreature); + if(!GetLocalInt(oObject, "AI_STATED_LOCKED_" + sID) && + !ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK)) SpeakString("That " + GetName(oObject) + " is locked!"); + SetLocalInt(oObject, "AI_STATED_LOCKED_" + sID, TRUE); + if(ai_GetAIMode(oCreature, AI_MODE_PICK_LOCKS) || + ai_GetAIMode(oCreature, AI_MODE_BASH_LOCKS)) + { + ai_AttemptToByPassLock(oCreature, oObject); + } + } + // Clear our action so we can move on to something else unless the door is open. + else if(!GetIsOpen(oObject)) + { + ai_ClearCreatureActions(); + } +}